A problem with AutoResetEvent

M

Maqsood Ahmed

Hello,

We have been experiencing a problem with AutoResentEvent class for past
2-3 months. It seems that it just stops at WaitOne and the thread
doesn't released from blocking state. We have been using the following
code for past 4 years, and It was working perfectly fine till Nov-Dec
last year. I suspect a security update had messed it up. Please have a
look at the following code.
[Please note that we are using .NET Framework 1.1 SP1 for development]

-----------------------------------
Thread 1:
--------
public void IRCSendQueue(XmlDocument doc, string ircdest,bool
bExpectAck)
{
lock(queueIRCSend)
{
queueIRCSend.Enqueue(new IRCSendStruct(doc,ircdest,bExpectAck));
}
ircSendSignal.Set();
}

Thread 2:
--------
protected void IRCSendingThread()
{
//Event Processing
IRCSendStruct ircSendStruct;
try
{
while(ircclient.Connected)
{
ircSendSignal.WaitOne();
while(queueIRCSend.Count > 0)
{
lock(queueIRCSend)
{
ircSendStruct = (IRCSendStruct)queueIRCSend.Dequeue();
}
//Process IRC Message
this.IRCSend((ircSendStruct.expectAck)?ircSendStruct.doc.DocumentElement
..SelectSingleNode(Nodes.SEQNUM).InnerText:null,
Utility.DecodeXml(ircSendStruct.doc),ircSendStruct.ircdest);
}
}
}
catch(ThreadAbortException)
{
Log("IRC Sending Thread: Thread Abort", LogEntryType.INFORMATION,
null);
}
}
-----------------------------------
I put in logging before and after Set and WaitOne, It Sets the
AutoResetEvent but WaitOne never returns.

Thanks in advance.
Regards,

Maqsood Ahmed - MCAD.net
Kolachi Advanced Technologies
http://www.kolachi.net
 
J

Jon Skeet [C# MVP]

Maqsood Ahmed said:
We have been experiencing a problem with AutoResentEvent class for past
2-3 months. It seems that it just stops at WaitOne and the thread
doesn't released from blocking state. We have been using the following
code for past 4 years, and It was working perfectly fine till Nov-Dec
last year. I suspect a security update had messed it up. Please have a
look at the following code.
[Please note that we are using .NET Framework 1.1 SP1 for development]

It's hard to separate out the threading code from the rest in the
snippets you posted.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
N

Nicholas Paldino [.NET/C# MVP]

Maqsood,

I don't think you should be using an event in this case. You are using
a producer/consumer pattern, and you are better off using the lock
statement, along with the static Pulse and Wait methods on the Monitor
object. This is how I would write your code:

Thread 1:
--------
public void IRCSendQueue(XmlDocument doc, string ircdest,bool bExpectAck)
{
lock(queueIRCSend)
{
queueIRCSend.Enqueue(new IRCSendStruct(doc,ircdest,bExpectAck));

// Pulse the thread which will process the item placed in the
queue.
Monitor.Pulse(queueIRCSend);
}
}

Thread 2:
--------
protected void IRCSendingThread()
{
//Event Processing
IRCSendStruct ircSendStruct;

// Lock on the object here.
lock (queueIRCSend)
{
// Do while connected.
while (ircclient.Connected)
{
// Wait on the object.
Monitor.Wait(queueIRCSend);

// Perform processing here.
}
}
catch(ThreadAbortException)
{
Log("IRC Sending Thread: Thread Abort", LogEntryType.INFORMATION,
null);
}
}

Using this method, you should only have one thread that is listening
(the thread calling Monitor.Wait), while you can have multiple threads
sending process requests (the threads calling Pulse). When you call Pulse,
you are priming the thread that has called Wait to be called when you exit
the lock block.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Maqsood Ahmed said:
Hello,

We have been experiencing a problem with AutoResentEvent class for past
2-3 months. It seems that it just stops at WaitOne and the thread
doesn't released from blocking state. We have been using the following
code for past 4 years, and It was working perfectly fine till Nov-Dec
last year. I suspect a security update had messed it up. Please have a
look at the following code.
[Please note that we are using .NET Framework 1.1 SP1 for development]

-----------------------------------
Thread 1:
--------
public void IRCSendQueue(XmlDocument doc, string ircdest,bool
bExpectAck)
{
lock(queueIRCSend)
{
queueIRCSend.Enqueue(new IRCSendStruct(doc,ircdest,bExpectAck));
}
ircSendSignal.Set();
}

Thread 2:
--------
protected void IRCSendingThread()
{
//Event Processing
IRCSendStruct ircSendStruct;
try
{
while(ircclient.Connected)
{
ircSendSignal.WaitOne();
while(queueIRCSend.Count > 0)
{
lock(queueIRCSend)
{
ircSendStruct = (IRCSendStruct)queueIRCSend.Dequeue();
}
//Process IRC Message
this.IRCSend((ircSendStruct.expectAck)?ircSendStruct.doc.DocumentElement
SelectSingleNode(Nodes.SEQNUM).InnerText:null,
Utility.DecodeXml(ircSendStruct.doc),ircSendStruct.ircdest);
}
}
}
catch(ThreadAbortException)
{
Log("IRC Sending Thread: Thread Abort", LogEntryType.INFORMATION,
null);
}
}
-----------------------------------
I put in logging before and after Set and WaitOne, It Sets the
AutoResetEvent but WaitOne never returns.

Thanks in advance.
Regards,

Maqsood Ahmed - MCAD.net
Kolachi Advanced Technologies
http://www.kolachi.net
 
M

Maqsood Ahmed

Hello Mr. Nicholas Paldino,

Thanks for your reply. I will use this code snippet to see its affect
on the overall performance.

Regards,

Maqsood Ahmed
 
M

Maqsood Ahmed

Hello Mr. Paldino,

I tried the code you provided. Just some thoughts on it:

1. Don't you think that the 'lock' statement before Wait method will
produce a deadlock, because the Pulse method is also in the lock
statement.
2. Secondly, we are currently working on signal based communication
between threads. I don't think Monitor will allow us to do this. Here
are the two descriptions according to MSDN:

Monitor: "The Monitor class controls access to objects by granting a
lock for an object to a single thread".
AutoResetEvent: "AutoResetEvent allows threads to communicate with
each other by signaling".

We can use lock statements for granting a lock to a single thread
(similar to Monitor.Enter/Monitor.Exit).

3. Also, Will the Wait method proceed, if Pulse is called before Wait?
AutoResetEvent.Wait proceeds after .Set is called first.

Please clarify these doubts.

Thanks in advance,

Maqsood Ahmed
Kolachi Advanced Technologies
http://www.kolachi.net
 
J

Jon Skeet [C# MVP]

Maqsood Ahmed said:
I tried the code you provided.

And did it deadlock? Did it show any of the problems you were concerned
about?
Just some thoughts on it:

1. Don't you think that the 'lock' statement before Wait method will
produce a deadlock, because the Pulse method is also in the lock
statement.

No. Monitor.Wait releases the lock.
2. Secondly, we are currently working on signal based communication
between threads. I don't think Monitor will allow us to do this.

You're wrong - the Wait and Pulse methods are precisely there for
signalling.
3. Also, Will the Wait method proceed, if Pulse is called before Wait?
AutoResetEvent.Wait proceeds after .Set is called first.

No - Wait requires that Pulse is called *after* the call to Wait before
it will signal the waiting thread. Sometimes that's helpful, sometimes
it's not. A typical use of Wait has a while loop (within the lock) so
it knows whether or not to call Wait in the first place (and possibly
to call it multiple times).
 
Top