我有一个场景,我有两个线程 - 主要和工人(生产者/消费者) 主线程创建工作程序并等待其终止。 完成后,主线程想要访问worker的结果。
private object result;
private Exception exception;
public object Connect(int timeout)
{
Thread thread = ThreadHelper.StartNewBackground("Worker Thread", ConnectImpl);
if(!thread.Join(timeout))
throw new TimeoutException(string.Format("Connecting to the remote device has timed out ");
if (exception != null)
throw new ConnectFailedException(exception);
return result;
}
private void ConnectImpl()
{
try
{
result = ConnectToARemoteDevice();
}
catch(Exception ex)
{
exception = exc;
}
}
我不确定结果的同步(结果和异常字段)。在我看来,主线程可能没有看到更新的值。因此,我将ConnectImpl()重新实现为:
private void ConnectImpl()
{
try
{
Interlocked.Exchange(ref result, ConnectToARemoteDevice());
}
catch(Exception ex)
{
Interlocked.Exchange(refexception, ex);
}
}
或许我错了,没有必要?我不确定这是否必要,因为对于以下代码片段运行优化它不会运行不正确:
bool complete = false;
var t = new Thread (() =>
{
complete = true;
});
t.Start();
t.Join(); // comment this line to run undefinetly
bool toggle = false;
while (!complete) toggle = !toggle;
complete = true;
加入制作一些MemoryBarrier? 我使用的是.NET 3.5,所以我不能使用TPL,但也许你可以建议另一种机制/实现?
已解决 Are memory-barriers required when joining on a thread?加入正在制作MemoryBarrier。
答案 0 :(得分:0)
Join
方法使得调用线程块直到运行线程完成,因此它足够好同步。但是如果您创建另一个线程并等待它完成,那么它不是多线程的,为什么不在当前线程中运行该代码呢?在多线程环境中有许多不同的场景,但是你提供的代码片段没问题,没有上一个循环你应该有complete == true
,但还有更多......
在致电Join
之前,请务必检查线程是否存活:
if (t.IsAlive) t.Join();
加入已经注意到内存,内存总是共享。 我在调试中运行你的代码而没有阻塞,有或没有Join。
答案 1 :(得分:0)
加入正在制作MemoryBarrier。因此,不需要其他同步机制。 资源:Are memory-barriers required when joining on a thread?
答案 2 :(得分:0)
这是一个非常有趣的小问题,所以我必须回复一些细节。 是的,你是对的,在没有加入的发布模式下,它将永远运行。但是那个代码片段有点奇怪,你可能永远不会写那样的东西。
如果你像这样添加线程睡眠:
while (!complete) { toggle = !toggle; Thread.Sleep(1); }
你的程序会定期退出,所以也可以。
然而,如果你用MessageBox.Show替换Thread.Sleep,它也会定期退出,或者如果你只是添加一些额外的代码,它也可以。
bool complete = false;
var t = new Thread (() =>
{
/*MessageBox.Show("Thread started.");*/ // comment this out to not confuse you.
complete = true;
/*MessageBox.Show("Thread finished.");*/
});
t.Start();
//t.Join(); // comment this line to run undefinetly
bool toggle = false;
DateTime time = DateTime.Now;
while (!complete) {
toggle = !toggle; /*Thread.Sleep(1);*/
time = DateTime.UtcNow; }
MessageBox.Show("Main thread finished: " + time.ToString());
complete = true;
我不知道这背后究竟是什么,它有时候很难知道,但是做一些测试,最重要的是,依靠你自己的直觉。