[英]Is it safe to share local variable between threads (via a callback closure)?
我想做类似以下的事情 - 基本上我调用异步操作,它将在另一个线程中调用回调,我想等待它完成“内联”。 我担心的是,由于存储在寄存器中,因此跨线程共享的变量变量(bar和event)可能无法同步。 如果它们是成员变量,我可以将它们标记为volatile,但volatile不能用于堆栈上创建的局部变量。 我可以使用成员变量,但我认为它更干净,不会让我的课程整洁。
Bar bar = null;
ManualResetEvent event = new ManualResetEvent(false);
foo.AsyncOperation(new Action(()=>{
// This delegate will be called in another thread
bar = ...
event.Set();
}));
event.WaitOne(timeout);
// use bar
是的,它会正常工作。 在这里阅读
http://www.albahari.com/threading/part4.aspx
The following implicitly generate full fences:
Setting and waiting on a signaling construct
在信令结构中包含了ManualResetEvent
。
如果您想知道full fence
是什么,请在同一页面中:
完全围栏最简单的内存屏障是一个完整的内存屏障(全栅栏),可以防止任何类型的指令重新排序或围绕该围栏缓存。 调用Thread.MemoryBarrier会生成一个完整的栅栏;
我认为你的代码会起作用 - 即使它们只是堆栈变量,闭包也会提升到堆中(ManualReseetEvent肯定不会)。
但是为什么不把所有事情都放在event.WaitOne()之后的内部(块是event.Set被调用)? 我认为这应该是处理这种情况的首选方式,你不会以这种方式遇到麻烦(根本不需要外部块中的Bar,你仍然可以使用MRE来检查)。
我会考虑使用Task对象将其转换为Operations - 这将一次解决所有这些问题(例如从AsyncOperation返回一个Task)。 然后,您可以等待任务的结果并使用返回的Bar ...
class Foo
{
// ...
private Task<Bar> AsyncOperation(Task<Bar> initializeBar)
{
return initializeBar
.ContinueWith(
bar => {
/* do your work with bar and return some new or same bar */
return bar;
});
}
}
并像这样使用它:
var task = foo.AsyncOperation(Taks.Factory.StartNew(() => { /* create and return a bar */ }));
var theBar = task.Result; // <- this will wait for the task to finish
// use your bar
PS:闭包基本上将它们包装成一个类对象;)PPS:我很难在没有你的AsyncOperation的情况下测试这段代码,但是它应该通过错误的拼写/输入来模拟语法错误
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.