[thread] Never enter critical section [NC]
Hi, I'm having a problem with mutexes. In one thread T1 I have: while(!end) { /* TTT */ lock lk(mutex); dosomethingquick(); } In another thread T2 I have: void f() { lock lk(mutex); doanotherthingquick(); } I'm sure dosomethingquick returns but T2 can never acquires the mutex. If I had a timer on line /* TTT */ in T1 (sleeps for a millisecond), everything works fine. Can anyone understand such a behavior? Am I doing something wrong here? Thanks, ____________________________ Frederic MAYOT Société Générale - Equity IT 1221 Avenue of the Americas New York, NY 10020 +1 (212) 278-5558 +1 (917) 673-1339 ************************************************************************* This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither SOCIETE GENERALE nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified. *************************************************************************
On Thu, Aug 30, 2007 at 12:08:51PM -0400, frederic.mayot@sgcib.com wrote:
Hi, I'm having a problem with mutexes.
In one thread T1 I have: while(!end) { /* TTT */ lock lk(mutex); dosomethingquick(); }
I'm sure dosomethingquick returns but T2 can never acquires the mutex. If I had a timer on line /* TTT */ in T1 (sleeps for a millisecond), everything works fine.
Can anyone understand such a behavior? Am I doing something wrong here?
A guess: T1 reacquires the mutex before the OS actually dispatches T2 to run. Unlocking the mutex just makes "ready" one of threads waiting for it, but I'm not sure that it's required that the thread be immediately dispatched it onto (a) CPU. When you insert a volountary sleep in T1, the scheduler puts T1 to sleep and chooses another ready thread (T2 in this case) to run. Read on this: http://readlist.com/lists/vger.kernel.org/linux-kernel/31/156171.html
On Thu, Aug 30, 2007 at 12:08:51PM -0400, frederic.mayot@sgcib.com wrote: Hi, I'm having a problem with mutexes.
In one thread T1 I have: while(!end) { /* TTT */ lock lk(mutex); dosomethingquick(); }
I'm sure dosomethingquick returns but T2 can never acquires the mutex. If I had a timer on line /* TTT */ in T1 (sleeps for a millisecond), everything works fine.
Can anyone understand such a behavior? Am I doing something wrong here?
A guess: T1 reacquires the mutex before the OS actually dispatches T2 to run. Unlocking the mutex just makes "ready" one of threads waiting for it, but I'm not sure that it's required that the thread be immediately dispatched it onto (a) CPU. When you insert a volountary sleep in T1, the scheduler puts T1 to sleep and chooses another ready thread (T2 in this case) to run.
Oh yes, I know that. The thing is I don't know what to do. The code I gave is, in my opinion, something really common. I'm just wondering how other people do in such a case... It seems completely absurd that I would have to add a sleep just to help a thread acquiring a mutex!! The NPTL does not offer fair mutexes (hence, neither boost). Leaving my code as is, the only workaround I see would be to use an atomic variable v. T2 sets v to true at the beginning of f() and sets it back to false at the end. T1 would sleep only if the variable is true. What an ugly patch!! ************************************************************************* This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither SOCIETE GENERALE nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified. *************************************************************************
Hi Frederic,
The code I gave is, in my opinion, something really common. I'm just wondering how other people do in such a case...
This probably doesn't help much, but we ran into the same problem when using pthreads directly. One thread ran while another completely starved. The only solution we found was to include a call to pthread_yield after pthread_mutex_unlock in our ReleaseMutex routine. This fixed the starvation and didn't have a huge impact on performance. - Dave On Thu, 2007-08-30 at 13:49 -0400, frederic.mayot@sgcib.com wrote:
On Thu, Aug 30, 2007 at 12:08:51PM -0400, frederic.mayot@sgcib.com wrote: Hi, I'm having a problem with mutexes.
In one thread T1 I have: while(!end) { /* TTT */ lock lk(mutex); dosomethingquick(); }
I'm sure dosomethingquick returns but T2 can never acquires the mutex. If I had a timer on line /* TTT */ in T1 (sleeps for a millisecond), everything works fine.
Can anyone understand such a behavior? Am I doing something wrong here?
A guess: T1 reacquires the mutex before the OS actually dispatches T2 to run. Unlocking the mutex just makes "ready" one of threads waiting for it, but I'm not sure that it's required that the thread be immediately dispatched it onto (a) CPU. When you insert a volountary sleep in T1, the scheduler puts T1 to sleep and chooses another ready thread (T2 in this case) to run.
Oh yes, I know that. The thing is I don't know what to do. The code I gave is, in my opinion, something really common. I'm just wondering how other people do in such a case... It seems completely absurd that I would have to add a sleep just to help a thread acquiring a mutex!! The NPTL does not offer fair mutexes (hence, neither boost). Leaving my code as is, the only workaround I see would be to use an atomic variable v. T2 sets v to true at the beginning of f() and sets it back to false at the end. T1 would sleep only if the variable is true. What an ugly patch!! ************************************************************************* This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither SOCIETE GENERALE nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified.
************************************************************************* _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
David Daeschler wrote:
This probably doesn't help much, but we ran into the same problem when using pthreads directly. One thread ran while another completely starved. The only solution we found was to include a call to pthread_yield after pthread_mutex_unlock in our ReleaseMutex routine. This fixed the starvation and didn't have a huge impact on performance.
Does someone understand the rationale for this implementation? Thanks, Sohail
Does someone understand the rationale for this implementation?
The rationale for the implementation is that the second thread wasn't given the opportunity to acquire the mutex because pthread_lock/unlock doesn't guarantee that the first thread won't just grab it again. We needed a way to prevent this, as it was happening every time. Summed up pretty well here, it seems like it's up to the OS scheduler and the scheduling policy who gets the mutex: http://www.redhat.com/archives/phil-list/2004-February/msg00027.html (that entire thread is pretty interesting) Linux behaved in a different manner than other OSs we had compiled on. It kept giving the mutex to the first thread every time (which looks to be an acceptable behavior). pthread_yield() allowed the component to work properly under Linux until we had more time to figure out what was happening. Yielding the remainder of the time slice must have given the second thread enough time to acquire the mutex. We ended up restructuring the code to prevent the problem in the future, but this may not be an option for everyone.
On Thu, Aug 30, 2007 at 12:08:51PM -0400, frederic.mayot@sgcib.com wrote: Hi, I'm having a problem with mutexes.
In one thread T1 I have: while(!end) { /* TTT */ lock lk(mutex); dosomethingquick(); }
...
Oh yes, I know that. The thing is I don't know what to do. The code I gave is, in my opinion, something really common. I'm just wondering how other people do in such a case...
The code is totally and irrecoverably broken (from a threading perspective). There is no way to fix it if it has to retain its current form. The basic idea when using threads is to create parallelism. Thread T1 is inherently non-parallel. It simply cannot operate in parallel with anyone else who also needs to access the shared state that is protected by the mutex. As a simplified example, consider two threads of the above form. Given a "fair" mutex, they will be effectively equivalent to (and slightly slower than) a single thread that does: while( !end ) { dosomething_t1(); dosomething_t2(); } This may sound a bit unproductive, but it's hard to offer a general advice without knowing the specifics. As given, thread T1's effort is obviously wasted (it spins its wheels in place) so it has to be made to only wake up when it really has work to do.
The code is totally and irrecoverably broken (from a threading perspective). There is no way to fix it if it has to retain its current form.
Well... let's take the example of an interruptible task. We have a main program which launches a thread. Now, we want to stop this thread. We can use interruption or the following code: T1: while(true) { lock lk(mutex); if (end) break; /* dosomething */ } T2: interruptT1() { lock lk(mutex); end = true; }
The basic idea when using threads is to create parallelism. Thread T1 is inherently non-parallel. It simply cannot operate in parallel with anyone
else who also needs to access the shared state that is protected by the mutex.
That's what I call contention (when your threads work in a collaborative way)... ************************************************************************* This message and any attachments (the "message") are confidential and intended solely for the addressees. Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither SOCIETE GENERALE nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified. *************************************************************************
Well... let's take the example of an interruptible task. We have a main program which launches a thread. Now, we want to stop this thread. We can use interruption or the following code:
T1: while(true) { lock lk(mutex); if (end) break;
lk.unlock();
/* dosomething */ }
T2: interruptT1() { lock lk(mutex); end = true; }
T2 only needs access to 'end', it doesn't touch the shared state modified by 'dosomething', so it doesn't need to be prevented from running in parallel with 'dosomething'. The general rule is to keep the critical regions as short as possible and not reuse the same mutex for unrelated tasks. In this specific case one can also use an atomic variable, of course.
participants (5)
-
David Daeschler
-
frederic.mayot@sgcib.com
-
Peter Dimov
-
Sohail Somani
-
Zeljko Vrba