开发者

What is the best way to wait for a variable in a multithreaded application

开发者 https://www.devze.com 2022-12-16 02:52 出处:网络
I would like to do something like the below for a开发者_运维百科 multi-threaded program: // wait for variable to become true but don\'t hog resources

I would like to do something like the below for a开发者_运维百科 multi-threaded program:

// wait for variable to become true but don't hog resources  
// then re-sync queues  

Is something like this a good solution?

while (!ready) {
    Thread.Sleep(250); // pause for 1/4 second;
};


No, this is not a good solution. First it might sleep too long. Second it's easy for threads to get into lockstep. Here's couple of links to MSDN articles on proper synchronization techniques:

  • Conditional variables
  • Events


Here's how you do it using boost:

boost::condition_variable condvar;
boost::mutex mutex;
bool finished1 = false;
bool finished2 = false;

void longComputation1()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = true;
    }
    condvar.notify_one();
}

void longComputation2()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = true;
    }
    condvar.notify_one();
}

void somefunction()
{
    // Wait for long computations to finish without "spinning"
    boost::lock_guard<boost::mutex> lock(mutex);
    while(!finished1 && !finished2)
    {
        condvar.wait(lock);
    }

    // Computations are finished
}

For the sake of brevity, I didn't include the thread spawning code.

The boost::lock_guard uses the RAII idiom to automatically unlock the mutex when the lock object goes out of scope. Very useful for preventing deadlocks in case of exceptions.

I find condition variables less error prone than Microsoft's Event objects. If you use boost.Thread, you'll have the added benefit of cross-platform potability.


Try to use Event (kernel object) instead of simple variable and replace your loop by:

WaitForSingleObject(hEventHandle, INFINITE);


The code above will work, and maybe appropriate in some circumstances.

You could also look at a critical section or semaphore - this will make your application block and wait until the resource becomes available,

Your thread that does the work grabs the mutex, does some work, meanwhile, the main method also tries to grab the same mutex, but can't. when the worker thread(s) exit, they release the mutex and your main thread can pass the critical section and continue.


First of all, you need to declare your 'ready' variable at least 'volatile' or this could have nasty side effects. Secondly, sleeping that long vefore reevaluating the condition is only a good idea if the duration it might take is indeed very long, let's say a few minutes.

Using the WinAPI's Event functions (CreateEvent, SetEvent(), WaitForSingleEvent()) is the best way to do it. Of course it introduces some overhead, but usually it's fine.

If you want to stick with your solution, looping and rechecking the condition a few times before you sleep again could improve performance in some scenarios.


The raw Win32 API has EVENT for doing this, here's a usage example:

http://msdn.microsoft.com/en-us/library/ms686915(VS.85).aspx

However, that API is C-oriented and particular to Windows. If writing a C++ program you might consider making your code more platform independent by using something like boost::threads, which has an analogue in Conditions.

A caveat I've found is that Windows can WaitForMultipleObjects, thus waiting on several events (and other handle classes) at a time. boost has no parallel AFAIK.


On top of good answers already provided - you will waste half the sleep time, assuming a random distribution of the occurrence you wish to detect. 125ms is an eternity in computer time.

WaitForSingleObject on a Win32 Event handle allows you to detect the required signal pseudo-immediately (depending on what other threads in your process are doing), and not do redundant checks (how many needless loops do you have to execute before the signal arrives?), provided the setting thread call SetEvent once it's done with its work. The bool is then redundant, which is as it should be.


Granted this is C#, but I've found this book to be extremely helpful for doing multi-threading development.

http://www.albahari.com/threading/

Some of the info is not language specific.

0

精彩评论

暂无评论...
验证码 换一张
取 消