1

In the title is pretty clear, I just need to know if there's a way to Sleep for some miliseconds and then call a function without stopping the GUI. The way that I do now is just adding Sleep(3000); and this makes the GUI Freezes until the Sleep time is done.

I tried to add Sleep() in a thread and then call a function, but it doesn't work, because the function makes modifications in the GUI Elements, and Threads doesn't let you access the GUI Elements (like label, buttons...).

So what should I do to make my code wait a few seconds to continue, but without stopping the GUI?

btw the Sleep is inside of a backgroundWorker_RunWorkerCompleted (which is just the callback of BackgroundWorker after the backgroundworker is done).

void backgroundWorker_RunWorkerCompleted(Object^ /*sender*/, RunWorkerCompletedEventArgs^ e){

     printf("Done, Waiting 3 seconds to do something that has to be 3 seconds after.");
     Sleep(3000); //at this point the UI freezes
     this->CallFunction();     

}

Any tips/suggestions of how to do this?

Grego
  • 2,220
  • 9
  • 43
  • 64

4 Answers4

1

You mention a GUI, but don't mention any particular UI framework. I'll assume WinAPI for the time being but conceptually the vast majority of other frameworks have what I'm about to mention.

In Win32, you can use timers to achieve what you want. In your WM_CREATE or WM_INITDIALOG, etc. set a timer with SetTimer. The system then takes the time-out value you supplied and each time that value elapses, it will notify your window with a WM_TIMER message. SetTimer returns immediately so will not block your UI thread.

An alternative way you can do this is to kick off a new thread at the start. This new thread will do the sleeping and do whatever work needs to be done every 3 seconds. Since it is done in a separate thread, the UI will not lock up. You should always return quickly/immediately from a WndProc. If a lot of work needs to be done, that work should be delegated to another thread which will do the heavy lifting.

Mike Kwan
  • 24,123
  • 12
  • 63
  • 96
0

Have your background thread set a flag to a mutexed variable on your main thread which tells it (the main thread) that it is safe to continue doing whatever it is doing. It's sort of like a stop light -- all corners (both sides) have lights that are inter-related.

Your main thread will not pause, but you can have a while loop where you handle (gui and other) messages but it won't break the loop until the mutexed variable get's set -- and that will occur on the background thread.

Here are some references to get you started:

EDIT -- Per request:

Globally, define your mutex handle and your variable:

HANDLE sharedMemoryMutex = CreateMutex(NULL, FALSE, "My mutex =)!");
BOOL good2Go = false;

Then, in your background thread, it will look something like this:

void wait() {
    // First, we sleep...
    sleep(3000);

    // Now, we request a lock on the good2Go variable, so that when we write to
    // it, no other thread is:
    DWORD dwWaitResult = WaitForSingleObject(sharedMemoryMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED) {
    if (dwWaitResult == WAIT_ABANDONED) {
            // Shared memory is maybe in inconsistent state because other program
            // crashed while holding the mutex. Check the memory for consistency
            ...
    }

    // Access your shared memory
    good2Go = true;

    // Release the lock so that the main thread can read the variable again..
    ReleaseMutex(sharedMemoryMutex);
}

Then in your main thread, it will look something like this:

// Create your background wait thread:
// .....

while(true) {

    // Handle messages so that your program doesn't appear frozen.
    // You will have to do your research on this one =)
    YourMessageHandler();

    // Request a lock on the good2Go variable, so we can read it w/o corrupting it
    DWORD dwWaitResult = WaitForSingleObject(sharedMemoryMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED) {
    if (dwWaitResult == WAIT_ABANDONED) {
            // Shared memory is maybe in inconsistent state because other program
            // crashed while holding the mutex. Check the memory for consistency
            ...
    }

    // Exit the loop
    if( good2Go ) { ReleaseMutex(sharedMemoryMutex); break; }
    ReleaseMutex(sharedMemoryMutex);
}

// Continue your code after the 3 pause....

You will have to figure out how to handle messages if you do not know already. Also, your mutex implementation may be different, however you said you're using VC so the above win32 implementation should be okay. And I think you understand the general concept

Community
  • 1
  • 1
Authman Apatira
  • 3,994
  • 1
  • 26
  • 33
  • hmm, could you show me what you mean with a piece of code for better visualization? and also I use mutexes in my code to make the other thread wait when altering the same variable, but I don't understand how to do it in Visual C++/CLI as in my example. Show me some code example. – Grego Apr 10 '12 at 14:20
0

Since you're using VC++/CLI, it is a close cousin of C#. You should look here to see how to update a GUI from another thread:

How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Tommy Hui
  • 1,306
  • 6
  • 9
0

Quick fix: Put your Sleep call inside the BackgroundWorker task, not in the RunWorkerCompleted event handler. The event handler runs on the GUI thread.

Better fix: Learn about timers like Mike suggested. WinForms provides timers which will fire an event after a delay of your choice. Starting a background task just to have it sleep and exit is a terrible waste.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720