0

I'm developing an application that needs to check the DB every 5 sec (with a query) and when it happens, the GUI freezes for about 0.5sec and that its really annoying.

This is my code, I'm using "System.Windows.Forms.Timer" but i can change it.

private void TimerBackground(Object myObject, EventArgs eventArgs)
{
    // code to check from DataBase that takes about 0.5 sec and freezes the GUI
    // Then it will display the result to a label in a form
}
void main(){
    System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
    myTimer.Tick += new EventHandler(TimerBackground);
    myTimer.Interval = 5000;
    myTimer.Start();
}

Is there a better way to do this?

EDITED: Im using a simple query, like this:

string credentials = "Server=127.0.0.1;port=3306;Database=test;Uid=root;password=root;";
MySqlConnection conn = null;
try
{
    conn = new MySqlConnection(credentials);
    MySqlCommand command = conn.CreateCommand();
    command.CommandText = "SELECT * FROM myTable;";
    conn.Open();
    MySqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        //...
    }
}
catch { }
finally { if (conn != null)conn.Close(); }

[SOLVED]

Well, i was reading the comments and i decided to investigate about await which solved my problem. I simply wrote this inside my "Timer Function" (TimerBackground):

private async void TimerBackground(Object myObject, EventArgs eventArgs)
{
    // This prevents the GUI from freezing.
    await Task.Run(() =>
    {
       runQueryFunction();
    });
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
suffuko
  • 143
  • 1
  • 2
  • 12

2 Answers2

0

You can use Background Workers or Threads for that. Using Timer control will freeze the UI because Timer controls always run on the same thread from where they were called!

Community
  • 1
  • 1
Jamshaid K.
  • 3,555
  • 1
  • 27
  • 42
  • 1
    The OP's operation is IO bound, not CPU bound, so there's no reason to create an additional thread just so it can sit there and do nothing while the query runs. – Servy Mar 16 '17 at 19:34
  • Oh! I thought he is asking for alternative solution to Timer control – Jamshaid K. Mar 16 '17 at 19:36
  • I don't see how there is anything wrong with this answer. There should be no problem using a separate thread here. – Adam Heeg Mar 16 '17 at 19:55
  • 2
    I tend to agree with @Servy - this sounds more like a task for non-blocking I/O like you can get from async/await than creating a separate thread. See my answer [here](http://stackoverflow.com/a/41247053/4032703) talking about why it's better to use non-blocking I/O rather than separate threads for I/O bound work. – EJoshuaS - Stand with Ukraine Mar 16 '17 at 20:14
  • @AdamHeeg So you regularly go around creating threads just for no reason...just because you like using up system resources for the heck of it? May I ask why you suggest doing such a thing? – Servy Mar 16 '17 at 20:17
  • 1
    @Servy I would be interested to hear your suggested approach that doesn't involve starting a new thread – Joe Irby Mar 16 '17 at 20:35
  • @JoeIrby The DB provider has an asynchronous method, you just call that instead of the synchronous method. – Servy Mar 16 '17 at 20:53
  • @Servy Creating a single thread to run a process that does a DB operation every 5 seconds sounds pretty smart to me. It isn't a new thread per call, but for the loop. There could be any number of reasons to not lock the UI for this, not the least of which is I bet every user isn't always interested in the query every 5 seconds. Stop punishing users. – Adam Heeg Mar 17 '17 at 17:21
  • @AdamHeeg I'm not suggesting that the UI needs to be blocked, the point is that *there is no reason to create a UI thread to avoid blocking the UI*. You might like to go around creating threads to *literally do nothing* constantly in your programs, because apparently you just don't care, but that doesn't make it a good idea. – Servy Mar 17 '17 at 17:28
  • @Servy no one said to make a UI Thread. All threads aren't UI Threads. You're making a straw man argument. http://stackoverflow.com/questions/5471626/background-thread-vs-ui-thread – Adam Heeg Mar 17 '17 at 18:38
  • @AdamHeeg I meant to say that there's no reason to create a thread (not a UI thread) to avoid blocking the UI. There's no reason to create a non-UI thread just to have it sit there doing nothing for a long period of time. – Servy Mar 17 '17 at 18:42
  • @Servy a .5 second delay to the user EVERY 5 seconds is a pretty good reason to spawn a background worker. If it doesn't work then that is another story (I don't know if it will, but I think trying it is valid). If it can be solved in another way, then I'm with you. But imho writing a product that is user friendly is worth the cost in this case. – Adam Heeg Mar 17 '17 at 19:07
  • @AdamHeeg Like I said, I'm not advocating blocking the UI. I'm saying that creating a thread that's going to sit there doing nothing for a while is unnecessary, and that you can ensure the UI isn't blocked *without wasting those resources*. If you are expecting a letter to come in the mail in 3 days do you sit by your mailbox for 3 days waiting for it? If you have things to do during the next three days do you hire someone to sit next to your mailbox to wait for your letter for you? Or do you just go do other things *without having anyone sit next to the mailbox* and check on it in 3 days? – Servy Mar 17 '17 at 19:21
  • You're effectively claiming that the second option (hiring someone to sit next to your mailbox and do nothing until your letter arrives) is the only option because you have things to do in the next three days and can't wait yourself – Servy Mar 17 '17 at 19:21
0

As I understand the question, the timer and its event are working fine, but the read operation from the database is causing a delay in the gui. One option is to use a thread for the read operation:

protected virtual void MyHandler(object sender, args e)
{
new Thread(() => {
myDatabaseObject.QueryForSomething();
}).Start();
}

This may not be the best threading method, but it communicates the idea.

Then, maybe add an event in the database object to fire if whatever you're looking for comes back true. I'd expect that this approach would not involve any noticeable delay in the gui.

Kevin Fichter
  • 1,067
  • 1
  • 11
  • 17
  • The database operation isn't going to be CPU bound, and as such there is no reason to create another thread. – Servy Mar 16 '17 at 20:17
  • Servy fair point, but wouldn't the main thread be waiting on that IO operation, so wouldn't making the IO asynchronous relieve the issues the OP mentioned? Perhaps async/await as @EJoshuaS suggested? Ultimately, if asynchronicity doesn't resolve the OP's problem, what will? – Kevin Fichter Mar 16 '17 at 20:29
  • Asynchrony != multithreaded. The operation needs to be asynchronous, but there's no reason at all to create another thread to accomplish that. The IO is already inherently asynchronously, so you're performing an asynchronous operation, blocking the current thread while that happens, and then creating a new thread just so that it can sit there and do nothing until the underlying asynchronous operation finishes. The solution is to just use the asynchronous operation to begin with, rather than to create a thread that does nothing while it runs. – Servy Mar 16 '17 at 20:31
  • `await` is just a useful language feature for making composing asynchronous operations easier to write; that's all. It doesn't make things inherently asynchronous, and you don't need to use it to write asynchronous code. – Servy Mar 16 '17 at 20:32