Locking and Async NetworkStream Operations

G

Guest

Hey all

While working with Async Methods and Networking I found something very
strange or better a bug?

To test it yourself create a new Windows Application with just a Button on
the Form.

Then modify the Code of the Form1 class until it looks like:

/****** BeginCode ******/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Net;

namespace WindowsApplication1 {
public partial class Form1 : Form {
TestClass c;
TcpClient cl;

public Form1() {
InitializeComponent();

Thread tr = new Thread(new ThreadStart(AcceptStuff));
tr.Start();

c = new TestClass();
}

public void AcceptStuff() {
TcpListener tcp = new TcpListener(IPAddress.Any, 1234);
tcp.Start();
cl = tcp.AcceptTcpClient();
}

private void button1_Click(object sender, EventArgs e) {
c.Add("bla");
}
}

class TestClass {
private object myLock = new object();
private MemoryStream m_memStream = new MemoryStream();
private NetworkStream m_netStream;

public TestClass() {
TcpClient tcp = new TcpClient("localhost", 1234);
m_netStream = tcp.GetStream();
}

public void Add(string bla) {
lock(myLock) {
Console.WriteLine("Lock1 locked");
byte[] buffer = Encoding.ASCII.GetBytes(bla);
m_netStream.BeginWrite(buffer, 0, buffer.Length, new
AsyncCallback(BeginWriteCallback), this);
Thread.Sleep(100);
Console.WriteLine("Lock1 unlocked");
}
}

private static void BeginWriteCallback(IAsyncResult ar) {
TestClass t = (TestClass)ar.AsyncState;
lock(t.myLock) {
Console.WriteLine("Lock2 locked");
t.m_netStream.EndWrite(ar);
Console.WriteLine("Lock2 unlocked");
}
}
}
}
/****** EndCode ******/


Now Point the Click-Event of your button to the Function:
button1_Click.

Now run the Application and Press the Button once.
You should see 4 Lines in your Debug View:
Lock1 locked
Lock1 unlocked
Lock2 locked
Lock2 unlocked

Looks good so far.

Now press the Button again and again and somewhen you'll see those 4 Lines:
Lock1 locked
Lock2 locked
Lock2 unlocked
Lock1 unlocked

Whao an already locked Object gets locked again?

Did I missunderstand something about the lock Statement? Or what's wrong
with it?
It's rather strange that this only occurs with the Async Method of a
NetworkStream, if I change it to a MemoryStream, it does never fail.

I guess this happens because the Async-Method is started from within the
Lock and when the Callback is fired, it somehow still thinks it's in that
locked Code-Part and doesn't try to lock again.
But it only happens sometimes and sometimes it does work (as you could test
yourself with the code above).

So anyone noticed something similiar? Is this a Bug in the Framework? Is
there any workaround?

Thanks for help

//Roman
 
V

Vadym Stetsyak

Did I missunderstand something about the lock Statement? Or what's wrong
with it?
It's rather strange that this only occurs with the Async Method of a
NetworkStream, if I change it to a MemoryStream, it does never fail.

I guess this happens because the Async-Method is started from within the
Lock and when the Callback is fired, it somehow still thinks it's in that
locked Code-Part and doesn't try to lock again.
But it only happens sometimes and sometimes it does work (as you could
test
yourself with the code above).

So anyone noticed something similiar? Is this a Bug in the Framework? Is
there any workaround?

The situation you've described may happen when BeginWrite completes
synchronously ( it is not a bug ). This means that callback is executed from
within BeginWrite and in the same thread, that is why you reenter the lock
without blocking.

Why do you use locking here?
 
Y

Yuan Ren[MSFT]

Hi Roman,

Thanks for posting!

As Vadym mentioned, if the current thread is not very busy, it will execute
the Asynchronous method by itself. Actually, this issue is not happened
frequently. So this is not a bug issue.

In addition, if you want to execute these methods synchronously, I don't
understand why you will choose the asynchronous callback method? Could you
please give me more explanation about the current issue? Thanks for your
understanding!

Regards,

Yuan Ren [MSFT]
Microsoft Online Support
 
G

Guest

The situation you've described may happen when BeginWrite completes
synchronously.

That single sentence cleared up so many things thanks!
Well in that example locking might not make sence.

About why I need a Lock:
Let's say we have a List somewhere in the TestClass and some functions to
access it, add elements or remove elements. And because a thread could add an
element while the Callback is working with the list, I need to "lock" the
List for synchronizing List access.
I know, blocking on a Callback is evil but I don't see much other
possibilities.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top