Modify a class property from another thread in C#
I have a C# class that executes an infinite loop until a conditional variable is set to true. There's another class that waits for a network message and when the message is received there's a call to the other class to modify the c开发者_如何学Pythononditional variable to true so it can exit the while loop. The waiting for the message is done in a separate thread:
The modifier class:
public class Modifier{
Otherclass log;
private static NetworkStream theStream;
private StreamReader theInput;
public Modifier(Otherclass other, NetworkStream str)
{
this.log = other;
theStream = str;
theInput = new StreamReader(theStream);
Thread listenThread = new Thread(new ThreadStart(listen));
listenThread.Start();
}
public void listen()
{
while (true)
{
log.postMessage(theInput.ReadLine());
}
}
}
And the other class:
public class Otherclass{
bool docontinue = true;
public void postMessage(string input)
{
docontinue = true;
}
public void wait()
{
while(!docontinue)
{
}
}
}
The problem is that the program gets stuck at the while(!docontinue) although a message is sent. I suspect that the problem is that the variable docontinue is not getting modified but I don't know if the problem is somewhere else.
There are various issues here -
The first, and direct answer to your question, is that you need to declare your boolean field using volatile:
private volatile bool doContinue = true;
That being said, having a loop that does a while loop with no body is very bad - it will use up 100% CPU on that thread, and just "spin" indefinitely.
A much better approach to situations like this is to replace your while loop with a WaitHandle, such as ManualResetEvent. This allows you to wait on the reset event, and block until you're ready to continue. You call Set() on it in the other thread to allow the execution to continue.
For example, try this:
public class Otherclass{
ManualResetEvent mre = new ManualResetEvent(false);
public void PostMessage(string input)
{
// Other stuff here...
mre.Set(); // Allow the "wait" to continue
}
public void Wait()
{
mre.WaitOne(); // Blocks until the set above
}
}
You have two (potentially) infinite loops here. And nothing actually ever calls Wait()
Is there a good reason why you need to waste cycles in a dummy loop inside the wait method? What purpose does it serve?
It seems to me, postMessage should kick off a new thread that will perform whatever work needs to get done after Wait() is supposed to break.
You can use Volatile
private volatile bool docontinue = true;
Try adding Thread.Sleep(100) in your cycle. Also consider using the ManualResetEvent class.
UPDATE: I've just checked, wait() exits even without Thread.Sleep, volatile and other things. But my test console app hangs because the listen() thead never ends...
Other people have pointed out that there are better ways to do this, but I wanted to point out an issue in the code you posted.
public class Otherclass{
bool docontinue = true;
public void postMessage(string input)
{
docontinue = true;
}
public void wait()
{
while(!docontinue)
{
}
}
}
docontinue
doesn't change values. It starts as true and you set it to true when the message is posted. On top of that you have a not in your while clause, so the loop should never run as !docontinue
is always false.
精彩评论