digitalmars.D.learn - What sync object should i use?
- Heinz (15/15) May 13 2013 Hi,
- Steven Schveighoffer (6/19) May 13 2013 core.sync.condition and core.sync.mutex
- Heinz (6/32) May 13 2013 Thanks Steve for your quick reply. You answered me before i fixed
- Heinz (32/47) May 13 2013 Damn, i hit enter and posted before completion, fail! Here's the
- Heinz (8/8) May 13 2013 Ok, here's a summary in case someone else is in the same need:
- Juan Manuel Cabo (38/47) May 13 2013 Here is the absolute minimum of code I could think to try
- Steven Schveighoffer (7/11) May 13 2013 Right, the equivalent to a windows event is a D Mutex, Condition, and a ...
- Juan Manuel Cabo (13/25) May 13 2013 Thanks!!! Your explanation finally made it clear for me. It would
- Steven Schveighoffer (6/8) May 13 2013 Well, whaddya know. Glad my former self could help :)
- Heinz (6/9) May 13 2013 Haven't had any issues calling notify outside a synchronized
- Dmitry Olshansky (9/17) May 14 2013 Have to lock it otherwise you have a race condition on a condition
- Heinz (25/34) May 14 2013 I can confirm that under Win32 calling notify() before wait()
- Dmitry Olshansky (5/28) May 14 2013 Wrong. Before setting it from some other thread you should grab the
- Heinz (126/126) May 14 2013 Guys, this is a precise example of what i'm trying to do. You'll
- Steven Schveighoffer (71/73) May 14 2013 2 things:
- Heinz (45/58) May 14 2013 Hmmm, i guess this is what the docs meant by "mutexes are
- Juan Manuel Cabo (18/34) May 15 2013 It sounds like you need to:
- Sean Kelly (3/7) May 15 2013 At which point I'll suggest considering std.concurrency instead
- Sean Kelly (8/14) May 14 2013 take the next iteration or wait until a thread calls SetLoop(true).
- Juan Manuel Cabo (12/22) May 14 2013 You also need to declare Condition as __gshared. If you don't,
- Sean Kelly (51/75) May 14 2013 and that is what happens when one issues a notify while the thread =
- Sean Kelly (20/20) May 14 2013 I'm doing this from my phone so please bear with me.
- Steven Schveighoffer (18/34) May 14 2013 s
- Dmitry Olshansky (26/54) May 14 2013 Never had to notify without sending some message (otherwise how you'd
- Sean Kelly (13/27) May 14 2013 or
- Steven Schveighoffer (14/23) May 14 2013 Any thread that does not check to ensure his data is ready while waiting...
Hi, I'm looking for an object in "core.sync" whose internal counter can be 0 or 1 (signaled/not signaled), just like Event Objects in Win32 (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396 28v=vs.85%29.aspx). The object must be waitable and able to notify waiters. A semaphore is the most similar thing but its internal counter can range from 0 to x. I can perfectly create and use an event under Win32 for my needs but i do not know their counterparts in FreeVSD, Linux and OSX; that's why i'm trying to use an already implemented object from the runtime. This is what i'm trying to do: void MyFunc() { }
May 13 2013
On Mon, 13 May 2013 15:41:47 -0400, Heinz <thor587 gmail.com> wrote:Hi, I'm looking for an object in "core.sync" whose internal counter can be 0 or 1 (signaled/not signaled), just like Event Objects in Win32 (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396 28v=vs.85%29.aspx). The object must be waitable and able to notify waiters. A semaphore is the most similar thing but its internal counter can range from 0 to x. I can perfectly create and use an event under Win32 for my needs but i do not know their counterparts in FreeVSD, Linux and OSX; that's why i'm trying to use an already implemented object from the runtime. This is what i'm trying to do: void MyFunc() { }core.sync.condition and core.sync.mutex I'd point at the docs, but they are poor. Search online for docs on how mutexes and conditions work. It's very similar to Windows events. -Steve
May 13 2013
On Monday, 13 May 2013 at 19:49:51 UTC, Steven Schveighoffer wrote:On Mon, 13 May 2013 15:41:47 -0400, Heinz <thor587 gmail.com> wrote:Thanks Steve for your quick reply. You answered me before i fixed my post. I'll take a look at what you say and post again here in case i have other questions.Hi, I'm looking for an object in "core.sync" whose internal counter can be 0 or 1 (signaled/not signaled), just like Event Objects in Win32 (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396 28v=vs.85%29.aspx). The object must be waitable and able to notify waiters. A semaphore is the most similar thing but its internal counter can range from 0 to x. I can perfectly create and use an event under Win32 for my needs but i do not know their counterparts in FreeVSD, Linux and OSX; that's why i'm trying to use an already implemented object from the runtime. This is what i'm trying to do: void MyFunc() { }core.sync.condition and core.sync.mutex I'd point at the docs, but they are poor. Search online for docs on how mutexes and conditions work. It's very similar to Windows events. -Steve
May 13 2013
On Monday, 13 May 2013 at 19:41:48 UTC, Heinz wrote:Hi, I'm looking for an object in "core.sync" whose internal counter can be 0 or 1 (signaled/not signaled), just like Event Objects in Win32 (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396 28v=vs.85%29.aspx). The object must be waitable and able to notify waiters. A semaphore is the most similar thing but its internal counter can range from 0 to x. I can perfectly create and use an event under Win32 for my needs but i do not know their counterparts in FreeVSD, Linux and OSX; that's why i'm trying to use an already implemented object from the runtime. This is what i'm trying to do: void MyFunc() { }Damn, i hit enter and posted before completion, fail! Here's the code: ///////////////////////////////////////////////// bool do_loop; // This function runs in its own thread. void MyFunc() { while(true) { if(!do_loop) myobject.wait(); // Wait for sync object. // ... Do other stuff. "do_loop" can be set to false again here. } } // This one is called by different threads. void loop(bool val) { do_loop = val; if(do_loop) // Release sync object if it is waiting. myobject.notify(); } ///////////////////////////////////////////////// The idea is that i have a code that loops and do a lot of stuff but sometimes i don't want it to loop so i set do_loop to false. When i want it to loop i set do_loop to true and release the waiting object. The problem of using a semaphore is that if i call loop() with true multiple times, my code will perform extra loops until the internal counter gets to 0, that's why i need a 0-1 sync object. Any suggestions? Thank you in advance.
May 13 2013
Ok, here's a summary in case someone else is in the same need: 1) Want to know what "mutex/condition" are, how do they work and when to use them? Here's a good resource: http://stackoverflow.com/a/4742236 2) If you come to the question "Why a condition needs a mutex?": http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex 3) Need a working example in D? (by Steven Schveighoffer): http://forum.dlang.org/thread/j7sdte$25qm$1 digitalmars.com
May 13 2013
On Monday, 13 May 2013 at 20:44:37 UTC, Heinz wrote:Ok, here's a summary in case someone else is in the same need: 1) Want to know what "mutex/condition" are, how do they work and when to use them? Here's a good resource: http://stackoverflow.com/a/4742236 2) If you come to the question "Why a condition needs a mutex?": http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex 3) Need a working example in D? (by Steven Schveighoffer): http://forum.dlang.org/thread/j7sdte$25qm$1 digitalmars.comHere is the absolute minimum of code I could think to try Condition. I tested it on linux 64bits and windows 32bits. There is one thing that should definitely added to the documentation, and that is what happens when one issues a notify while the thread hasn't yet called Condition.wait(). I seem to recall (though I might be wrong) that win32 events can be signalled before the thread calls WaitForSingleObject (or WaitForMultipleObjects), and if it was signalled, the call returns immediately. I think this was very useful. import std.stdio, core.thread, core.sync.condition, core.sync.mutex; //Note: The condition must be __gshared: __gshared Condition condition; __gshared Mutex mutex; private void myThread() { writeln("Started"); synchronized(mutex) { condition.wait(); } writeln("Notified"); } void main() { mutex = new Mutex(); condition = new Condition(mutex); Thread theThread = new Thread(&myThread); theThread.start(); //Note: if one doesn't wait for the thread to //get to condition.wait(), before calling notify(), //the thread is not awaken. (ie: commenting the //sleep makes the thread stuck). Thread.sleep(dur!"msecs"(100)); synchronized(mutex) { condition.notify(); } theThread.join(); writeln("main finished"); }
May 13 2013
On Mon, 13 May 2013 17:04:22 -0400, Juan Manuel Cabo <juanmanuel.cabo gmail.com> wrote:I seem to recall (though I might be wrong) that win32 events can be signalled before the thread calls WaitForSingleObject (or WaitForMultipleObjects), and if it was signalled, the call returns immediately. I think this was very useful.Right, the equivalent to a windows event is a D Mutex, Condition, and a protected boolean. In other words, the condition aids synchronization of a message, but it is not the message itself! Windows events could serve as the message (but not necessarily). -Steve
May 13 2013
On Monday, 13 May 2013 at 21:55:45 UTC, Steven Schveighoffer wrote:On Mon, 13 May 2013 17:04:22 -0400, Juan Manuel Cabo <juanmanuel.cabo gmail.com> wrote:Thanks!!! Your explanation finally made it clear for me. It would be nice if this last paragraph of yours was in the documentation. It would save some headakes for people like me (I first viewed Condition as a drop in replacement of win32 events, didn't know of the pthreads way). And also, after reading the other link posted above: http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex I think I finally got it. Thanks again! --jmI seem to recall (though I might be wrong) that win32 events can be signalled before the thread calls WaitForSingleObject (or WaitForMultipleObjects), and if it was signalled, the call returns immediately. I think this was very useful.Right, the equivalent to a windows event is a D Mutex, Condition, and a protected boolean. In other words, the condition aids synchronization of a message, but it is not the message itself! Windows events could serve as the message (but not necessarily). -Steve
May 13 2013
On Mon, 13 May 2013 16:44:36 -0400, Heinz <thor587 gmail.com> wrote:3) Need a working example in D? (by Steven Schveighoffer): http://forum.dlang.org/thread/j7sdte$25qm$1 digitalmars.comWell, whaddya know. Glad my former self could help :) BTW, given recent discussion on memory barriers, I think my previous statement that the mutex does not need to be locked to call notify is probably incorrect. -Steve
May 13 2013
BTW, given recent discussion on memory barriers, I think my previous statement that the mutex does not need to be locked to call notify is probably incorrect.Haven't had any issues calling notify outside a synchronized statement, even from multiple threads. At least this works under Win32 with my producer thread all wrapped inside synchronized(). Only a single consumer thread is inside synchronized() but then i have 2 more threads making naked calls to notify(). Not a single crash.
May 13 2013
14-May-2013 08:33, Heinz пишет:Have to lock it otherwise you have a race condition on a condition variable (wow!).BTW, given recent discussion on memory barriers, I think my previous statement that the mutex does not need to be locked to call notify is probably incorrect.Haven't had any issues calling notify outside a synchronized statement, even from multiple threads. At least this works under Win32 with my producer thread all wrapped inside synchronized(). Only a single consumer thread is inside synchronized() but then i have 2 more threads making naked calls to notify(). Not a single crash.Doesn't prove anything, it could happen that you just miss a notification, for instance. Another common case is that it so happens that wait will (with luck) always happen before any of notify and notifications come spaced out in time. -- Dmitry Olshansky
May 14 2013
On Monday, 13 May 2013 at 21:04:23 UTC, Juan Manuel Cabo wrote:There is one thing that should definitely added to the documentation, and that is what happens when one issues a notify while the thread hasn't yet called Condition.wait().I can confirm that under Win32 calling notify() before wait() internally signals the condition and then calling wait() returns immediately and actually does not wait. This is the expected behavior and is actually how Win32 events work. On Tuesday, 14 May 2013 at 08:58:31 UTC, Dmitry Olshansky wrote:Have to lock it otherwise you have a race condition on a condition variable (wow!).Ok, i'll lock it just in case. It also makes me feel my code is more robust. This will do right? ... synchronized(cond.mutex) cond.notify(); ... My internal bool variable that affects the condition (the one that decides if the consumer thread should wait) must be setable at any moment by any thread so i leave it outside the lock. Also, after setting this variable i immediately call notify() with mutex unlocked. That's why it is working i think.Doesn't prove anything, it could happen that you just miss a notification, for instance. Another common case is that it so happens that wait will (with luck) always happen before any of notify and notifications come spaced out in time.True, i guess my code work 100% as needed because of its implementation, in my case it doesn't matter if i miss a notification because the result of that notification gets evaluated in the next loop inside a while, but still most probably as you say wait() is always happening before a notification. A classic producer-consumer program must lock both calls, i do understand that.
May 14 2013
14-May-2013 20:09, Heinz пишет:On Monday, 13 May 2013 at 21:04:23 UTC, Juan Manuel Cabo wrote:There is one thing that should definitely added to the documentation, and that is what happens when one issues a notify while the thread hasn't yet called Condition.wait().I can confirm that under Win32 calling notify() before wait() internally signals the condition and then calling wait() returns immediately and actually does not wait. This is the expected behavior and is actually how Win32 events work.On Tuesday, 14 May 2013 at 08:58:31 UTC, Dmitry Olshansky wrote:Wrong. Before setting it from some other thread you should grab the lock. See Sean's example.Have to lock it otherwise you have a race condition on a condition variable (wow!).Ok, i'll lock it just in case. It also makes me feel my code is more robust. This will do right? ... synchronized(cond.mutex) cond.notify(); ... My internal bool variable that affects the condition (the one that decides if the consumer thread should wait) must be setable at any moment by any thread so i leave it outside the lock.Also, after setting this variable i immediately call notify() with mutex unlocked. That's why it is working i think.-- Dmitry Olshansky
May 14 2013
Guys, this is a precise example of what i'm trying to do. You'll notice that there're 2 ways of waking up the consumer: ///////////////////////////////////////////////////////////////////// Condition cond; // Previously instantiated. bool loop = false; // This variable determine if the consumer should take the next iteration or wait until a thread calls SetLoop(true). Object my_variable; // A value used for comunicating producer and consumer. It's not a prerequisite to be set for an iteration to happen. // This function is called by multiple threads. void SetLoop(bool val) { if(val != loop) { loop = val; if(loop) cond.notify(); // Wake up consumer in case it was waiting. } } // This function is called by multiple threads. bool GetLoop() { return loop; } void MyConsumer() { while(true) { synchronized(cond.mutex) { if(loop == false) cond.wait(); // Wait for producer or SetLoop(true). if(my_variable !is null) { /* ... Call private function 1. SetLoop(true/false) might be called here. ... */ my_variable = null; // Lock is useful here for setting my_variable. } // These conditions are intentionally placed here. if(loop == false) continue; // Jump to next iteration. Please note that cond.mutex gets released and reaquired in the next iteration. else loop = false; // Reset waiting on every iteration. Can be modified by private function 2 below. /* ... Call private function 2. SetLoop(true/false) might be called here. ... */ } } } void MyProducer() { while(true) { if(/* Some other condition */) { synchronized(cond.mutex) // Lock is useful here for setting my_variable. { my_variable = /* Some value */; cond.notify(); // Wake up consumer in case it was waiting. } } } } ///////////////////////////////////////////////////////////////////// Wouldn't wrapping all the lines in "SetLoop()" inside a "synchronized(cond.mutex)" statement produce a deadlock because it might be called by private functions 1 or 2? Should i only wrap cond.notify() or is it of no meaning in this case? Like this: void SetLoop(bool val) { if(val != loop) { loop = val; if(loop) { synchronized(cond.mutex) cond.notify(); // Wake up consumer in case it was waiting. } } } Synchronization of variable "loop" doesn't seem important in this case. Do you still recommend to use an extra mutex to set it? like this: void SetLoop(bool val) { synchronized(extra_mutex) { if(val != loop) { loop = val; if(loop) { synchronized(cond.mutex) cond.notify(); // Wake up consumer in case it was waiting. } } } } void MyConsumer() { //... if(loop == false) continue; else { synchronized(extra_mutex) loop = false; } //... } Thank you guys so much for your time and your expertise.
May 14 2013
On Tue, 14 May 2013 13:59:51 -0400, Heinz <thor587 gmail.com> wrote:Guys, this is a precise example of what i'm trying to do. You'll notice that there're 2 ways of waking up the consumer:2 things: 1. D mutex locks are re-entrant. That is, you can do: synchronized(mutex) { synchronized(mutex) { ... } } and all is fine. 2. The condition logic in your code is wrong. The condition/mutex protects the messages being sent to the consumer. It seems that you have two messages (which is OK): - my_variable is present, needs to be processed - Run function 2 (flag loop == run function 2), set from inside the consumer, and some undisclosed threads. I find this logic rather dangerous, but it is your app, I have no idea of the real meaning :) So I would do it like this (names TBD based on your real use case) void SetLoop(bool yesOrNo) { synchronized(cond.mutex) { if((loop = yesOrNo) == true) cond.notify(); } } void MyConsumer() { while(true) { Object _my_variable = null; synchronized(cond.mutex) { while(!loop && my_variable is null) // always wait for *real* messages to be set cond.wait(); _my_variable = my_variable; my_variable = null; // consume } // process local consumed copy of _my_variable *outside* of lock if(_my_variable !is null) { /* ... Call private function 1. SetLoop(true/false) might be called here. ... */ } // These conditions are intentionally placed here. synchronized(cond.mutex) { if(loop == false) continue; // Jump to next iteration. Please note that cond.mutex gets released and reaquired in the next iteration. else loop = false; // Reset waiting on every iteration. Can be modified by private function 2 below. } /* ... Call private function 2. SetLoop(true/false) might be called here. ... */ } } Then everything should be good. I'd also add a "SetMyVariable" function too, akin to SetLoop. -Steve
May 14 2013
To Steven:1. D mutex locks are re-entrant. That is, you can do: synchronized(mutex) { synchronized(mutex) { ... } } and all is fine.Hmmm, i guess this is what the docs meant by "mutexes are recursive", i didn't get it at first but now i do. To test this i wrapped SetLoop() in synchronized(cond.mutex) and called it from consumer wich was already all wrapped by the same synchronized(cond.mutex), i thought at first it was going to be a deadlock but i guess this is what you mean because it works like a charm. Thanks for your code example, i'll update my code with your suggestions. But there's one thing i don't understand in your example: If the producer is inside a while() generating multiple messages once in a while then when the lock is released in the consumer, the producer will replace "my_variable" a couple of times with the latest message until consumer gets to wait() again. That's why i locked the whole consumer, to sync all messages. Am i wrong here? To Sean:Let's back up a minute. Can you be more specific about what you're trying to do? I think you shouldn't need to use the "loop" var at all, but I'm not entirely sure. Also, loop and my_variable will be thread-local given how they're declared.Fair enough, i uploaded a bunch of code hoping that experienced programmers like you to understand right away what i'm doing. I have this "main loop" wich is named here as my consumer function. I didn't want this main loop to be cycling all the time if there was nothing to do. So i needed an event object (condition/mutex) that locked the loop until any of the 2 program events (or both) occur: 1) A custom program message was sent by producer to main loop to notify for example mouse move, key press, timer tick, etc. 2) The user explicitly want to do something else (execute custom code or perform an action not covered by program messages) or did something that now needs to be processed inside the main loop. In this case the user calls SetLoop(true) to notify the main loop and then do what the user want. That's why i have and need both types of messages: bool loop; and Object my_variable; My code seems to work fine but i did not know if it was the best approach. Now i know after your help that i can and must protect both messages with the condition's mutex and have all in sync. Also i learned that wait() and notify() must be inside a lock. To ALL: Sorry for my incompetence. I'm not new to D but i am to D2 and multithreading. I got stuck in D1, specially in the DMD1.030 era (those were the most stable and beautiful times) but now i decided it was time to evolve. So far, learning D2 and multithreading hasn't been easy, but with your help guys i've accomplished many things. Thank you again for your support.
May 14 2013
On Wednesday, 15 May 2013 at 02:25:02 UTC, Heinz wrote:.... I have this "main loop" wich is named here as my consumer function. I didn't want this main loop to be cycling all the time if there was nothing to do. So i needed an event object (condition/mutex) that locked the loop until any of the 2 program events (or both) occur: 1) A custom program message was sent by producer to main loop to notify for example mouse move, key press, timer tick, etc. 2) The user explicitly want to do something else (execute custom code or perform an action not covered by program messages) or did something that now needs to be processed inside the main loop. In this case the user calls SetLoop(true) to notify the main loop and then do what the user want. That's why i have and need both types of messages: bool loop; and Object my_variable; ....It sounds like you need to: 1) use a Message Queue. 2) Copy the message while you work on it with the consumer, so that you can exit the mutex. If you don't use a message queue, then the thread that feeds the consumer will have to wait on the consumer to finish processing the last message, just to post a new message. Thus removing the advantage of processing the message in a different thread. If you use a message queue, make it so that you exit the mutex lock while you process the message, and then reaquire the mutex to use the message queue. This is so that you can keep adding messages to the queue without having to wait until the last message is consumed. There are many ways to implement a queue for thread message passing, some are more advanced and require less locking. But you can start with a fixed array. --jm
May 15 2013
On Wednesday, 15 May 2013 at 15:35:05 UTC, Juan Manuel Cabo wrote:It sounds like you need to: 1) use a Message Queue. 2) Copy the message while you work on it with the consumer, so that you can exit the mutex.At which point I'll suggest considering std.concurrency instead of rolling everything yourself.
May 15 2013
On May 14, 2013, at 10:59 AM, Heinz <thor587 gmail.com> wrote:Guys, this is a precise example of what i'm trying to do. You'll =notice that there're 2 ways of waking up the consumer:=20 ///////////////////////////////////////////////////////////////////// Condition cond; // Previously instantiated. bool loop =3D false; // This variable determine if the consumer should =take the next iteration or wait until a thread calls SetLoop(true).Object my_variable; // A value used for comunicating producer and =consumer. It's not a prerequisite to be set for an iteration to happen. Let's back up a minute. Can you be more specific about what you're = trying to do? I think you shouldn't need to use the "loop" var at all, = but I'm not entirely sure. Also, loop and my_variable will be = thread-local given how they're declared.=
May 14 2013
On Tuesday, 14 May 2013 at 17:59:55 UTC, Heinz wrote:Guys, this is a precise example of what i'm trying to do. You'll notice that there're 2 ways of waking up the consumer: ///////////////////////////////////////////////////////////////////// Condition cond; // Previously instantiated. bool loop = false; // This variable determine if the consumer should take the next iteration or wait until a thread calls SetLoop(true). Object my_variable; // A value used for comunicating producer and consumer. It's not a prerequisite to be set for an iteration to happen.You also need to declare Condition as __gshared. If you don't, each thread will see a different Condition object or null, because by default, every D global variable goes to Thread Local Storage. Any variables meant to be shared between threads need to be either '__gshared' or 'shared'. You could also declare other shared data as 'shared', but I don't think that's what you want here. To list all global variables not declared as __gshared, you can compile using the -vtls switch. --jm
May 14 2013
On May 14, 2013, at 9:09 AM, Heinz <thor587 gmail.com> wrote:On Monday, 13 May 2013 at 21:04:23 UTC, Juan Manuel Cabo wrote: =20and that is what happens when one issues a notify while the thread = hasn't yet called Condition.wait().There is one thing that should definitely added to the documentation, ==20 I can confirm that under Win32 calling notify() before wait() internally signals the condition and then calling wait() returns immediately and actually does not wait. This is the expected behavior and is actually how Win32 events work.A Win32 event can be simulated basically like so: class Event { Condition c; bool signaled =3D false; this() { c =3D new Condition(new Mutex); } void wait() { synchronized (c.mutex) { while (!signaled) c.wait(); signaled =3D false; } } void notify() { synchronized (c.mutex) { signaled =3D true; c.notify(); } } } auto e =3D new Event; T get() { while (true) { e.wait(); // A -- race here synchronized (m) { if (!m.isEmpty()) return m.take(); } } } void put(T val) { synchronized(m) { m.add(val); } e.notify(); } You'll notice the redundancy here though to combat the race at point A. = Generally, you really want to avoid the Win32 model and use the = mutex/condition pair directly with your container or whatever.On Tuesday, 14 May 2013 at 08:58:31 UTC, Dmitry Olshansky wrote: =20variable (wow!).Have to lock it otherwise you have a race condition on a condition ==20 Ok, i'll lock it just in case. It also makes me feel my code is more robust. This will do right? =20 ... synchronized(cond.mutex) cond.notify(); =85Yep.My internal bool variable that affects the condition (the one that decides if the consumer thread should wait) must be setable at any moment by any thread so i leave it outside the lock. Also, after setting this variable i immediately call notify() with mutex unlocked. That's why it is working i think.I don't understand what you mean here. If the variable is protected by = a lock it can still be set by any thread at any time. Just only one = thread at a time. Doing a lock-free write of the variable basically = just means that the variable will probably be set eventually, which is = rarely what you actually want.=
May 14 2013
I'm doing this from my phone so please bear with me. You use a mutex in combination with a condition variable so you can check the state of something to determine if waiting is necessary. So the classic producer/consumer would be something like: T get() { shnchronized(c.mutex) { while (q.isEmpty) c.wait(); return q.take(); } } void put(T val) { synchronized (c.mutex) { q.add(val); c.notify(); } } You can emulate a Win32 event that stays flipped by checking/setting a bool or int inside the mutex.
May 14 2013
On Tue, 14 May 2013 04:58:27 -0400, Dmitry Olshansky = <dmitry.olsh gmail.com> wrote:14-May-2013 08:33, Heinz =D0=BF=D0=B8=D1=88=D0=B5=D1=82:BTW, given recent discussion on memory barriers, I think my previous=sstatement that the mutex does not need to be locked to call notify i=Have to lock it otherwise you have a race condition on a condition =probably incorrect.variable (wow!).No, the issue would be reordering (is that possible in this case?). The= = actual signaling of the condition would not require the lock, but you = still need to lock to send the message (e.g. set the boolean) or you wil= l = definitely have issues. But since you have to lock anyway, signaling while holding the lock, or = = while being outside the lock isn't really a difference. Maybe I'm wrong...t,Haven't had any issues calling notify outside a synchronized statemen=dseven from multiple threads. At least this works under Win32 with my producer thread all wrapped inside synchronized(). Only a single consumer thread is inside synchronized() but then i have 2 more threa=making naked calls to notify(). Not a single crash.Doesn't prove anything, it could happen that you just miss a =notification, for instance. Another common case is that it so happens ==that wait will (with luck) always happen before any of notify and =notifications come spaced out in time.I don't see how you could miss a notification, can you explain further? -Steve
May 14 2013
14-May-2013 21:02, Steven Schveighoffer пишет:On Tue, 14 May 2013 04:58:27 -0400, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:Never had to notify without sending some message (otherwise how you'd affect the thread on the other side of fence?). I'd have to dig into how D's condition variables are done to say for sure. But I thought that notify is not re-entrant that is it needs to be locked (as there is a queue of threads to manage). I just had fresh experience in Java where you basically can't notify threads waiting on the monitor without grabbing the lock, same with call to wait. It's a clean-cut run-time error (when it can detect it).14-May-2013 08:33, Heinz пишет:No, the issue would be reordering (is that possible in this case?). The actual signaling of the condition would not require the lock, but you still need to lock to send the message (e.g. set the boolean) or you will definitely have issues.Have to lock it otherwise you have a race condition on a condition variable (wow!).BTW, given recent discussion on memory barriers, I think my previous statement that the mutex does not need to be locked to call notify is probably incorrect.But since you have to lock anyway, signaling while holding the lock, or while being outside the lock isn't really a difference.On the level of gut feeling there must be something about it as you don't see: synchronized(m){ // ... send message } notify(); anytime of day. And hosting work out of mutex seems natural isn't it? Not in condition to analyze just yet but one clue is that it seems like you may be notifying a thread that would wake up only to block on mutex somebody else holds.Maybe I'm wrong...Maybe I am.Not particularly well put. In general I was implying that program not crushing doesn't mean anything useful. It might work either due to happenstance. Depending on the implementation of notify, if it's not re-entrant then technically anything fishy can happen. -- Dmitry OlshanskyI don't see how you could miss a notification, can you explain further?Haven't had any issues calling notify outside a synchronized statement, even from multiple threads. At least this works under Win32 with my producer thread all wrapped inside synchronized(). Only a single consumer thread is inside synchronized() but then i have 2 more threads making naked calls to notify(). Not a single crash.Doesn't prove anything, it could happen that you just miss a notification, for instance. Another common case is that it so happens that wait will (with luck) always happen before any of notify and notifications come spaced out in time.
May 14 2013
On May 14, 2013, at 12:02 PM, Dmitry Olshansky <dmitry.olsh gmail.com> = wrote:14-May-2013 21:02, Steven Schveighoffer =D0=BF=D0=B8=D1=88=D0=B5=D1=82:or=20 But since you have to lock anyway, signaling while holding the lock, =don't see:while being outside the lock isn't really a difference. =20=20 On the level of gut feeling there must be something about it as you ==20 synchronized(m){ // ... send message } notify(); =20 anytime of day. And hosting work out of mutex seems natural isn't it?If you move the notify out of the mutex then you can end up with = multiple threads competing for the same value. Say the producer puts a = value in the queue, leaves the mutex, and notifies a waiting thread. = Then consumer A enters the mutex, sees that there's something in the = container and takes it, then consumer B receives the notification and = wakes up to discover that the container is empty. So long as your wait = loops are done properly the only bad result will be pointless wakeups, = but worst case you could have a crash or exception if you're removing = data from the container without checking if it's empty.=
May 14 2013
On Tue, 14 May 2013 15:19:29 -0400, Sean Kelly <sean invisibleduck.org> wrote:If you move the notify out of the mutex then you can end up with multiple threads competing for the same value. Say the producer puts a value in the queue, leaves the mutex, and notifies a waiting thread. Then consumer A enters the mutex, sees that there's something in the container and takes it, then consumer B receives the notification and wakes up to discover that the container is empty. So long as your wait loops are done properly the only bad result will be pointless wakeups, but worst case you could have a crash or exception if you're removing data from the container without checking if it's empty.Any thread that does not check to ensure his data is ready while waiting for a condition, I would argue is incorrectly implemented -- cond.notify is not directly tied to the data, and there's always cond.notifyAll which could wake up any number of threads. I also don't think there's a requirement that threads waiting on a condition have priority over threads simply trying to lock. But I see little reason to avoid putting the cond.notify inside the lock. You HAVE to lock to insert the data anyway. And Dmitry seems to have some Java experience that indicates it's at least required there. I'd say go with notifying only while locked. I learn something every day :) -Steve
May 14 2013