Some Issues With Synchronized
Somedude
lovelydear at mailmetrash.com
Fri Dec 23 01:25:56 PST 2011
Le 22/12/2011 10:47, Andrew Wiley a écrit :
> I'm having some issues getting the synchronized modifier to work like
> a synchronized block. Sorry this code example is long, but here's
> three dummy implementations of a Condition-based work queue:
>
> ---import std.stdio;
> import core.sync.mutex;
> import core.sync.condition;
> import core.thread;
>
> synchronized class Queue1 {
> private:
> bool _work;
> Condition _cond;
> public:
> this() {
> auto lock = new Mutex(this); // initialize the monitor for
> this object so we can use the same lock in the Condition
> _cond = new Condition(lock);
> _work = false;
> }
> void doWork() {
> while(!_work) (cast()_cond).wait();
> _work = false;
> writeln("did work");
> return;
> }
> void addWork() {
> _work = true;
> (cast()_cond).notify();
> writeln("added work");
> }
> }
>
> class Queue2 {
> private:
> bool _work;
> Condition _cond;
> public:
> this() {
> auto lock = new Mutex(this); // again, initialize the monitor
> explicitly so we can reuse the lock
> _cond = new Condition(lock);
> _work = false;
> }
> synchronized void doWork() {
> while(!_work) (cast()_cond).wait();
> _work = false;
> writeln("did work");
> return;
> }
> synchronized void addWork() {
> _work = true;
> (cast()_cond).notify();
> writeln("added work");
> }
> }
>
> class Queue3 {
> private:
> bool _work;
> Condition _cond;
> Mutex _lock;
> public:
> this() {
> _lock = new Mutex(this); // make our own lock and ignore the monitor
> _cond = new Condition(_lock);
> _work = false;
> }
> void doWork() shared {
> synchronized(_lock) {
> while(!_work) (cast()_cond).wait();
> _work = false;
> writeln("did work");
> return;
> }
> }
> void addWork() shared {
> synchronized(_lock) {
> _work = true;
> (cast()_cond).notify();
> writeln("added work");
> }
> }
> }
>
> void main() {
> version(Q1) auto queue = new shared(Queue1)();
> version(Q2) auto queue = new shared(Queue2)();
> version(Q3) auto queue = new shared(Queue3)();
> auto thread = new Thread({
> while(true) queue.doWork();
> });
> thread.start();
> while(true) queue.addWork();
> }
> ---
>
> As you can see, this program starts a producer thread and a consumer
> thread, and it should endlessly print "did work" and "added work".
> Because the consumer has to wake up from the condition variable
> periodically, the producer tends to print far more often.
>
> So first, according to the D spec, I believe these three queues should
> behave identically. Is that true?
>
> Here's what happens:
> Queue1:
> DMD: crash
> GDC: crash
> Both print errors that look like this:
> core.sync.exception.SyncException at src/core/sync/mutex.d(159): Unable
> to unlock mutex
> From GDC's stack trace, it looks like the constructor call is
> being synchronized, so it crashes when I swap out the lock halfway
> through the constructor. Do we really need to synchronize constructor
> calls? I've never heard of another language that does this.
>
> Queue2:
> DMD: works
> GDC: deadlock
> Unless someone can see an issue here, I guess this is a GDC bug
> and should be handled separately.
>
> Queue3:
> DMD: works
> GDC: works
> This is about the most problematic way to do locking, but it does
> seem to work reliably.
On windows XP with DMD 2.057, I get
Queue1: deadlock
Queue2: works
Queue3: works
More information about the Digitalmars-d
mailing list