我想做类似以下的事情 - 基本上我调用异步操作,它将在另一个线程中调用回调,我想等待它完成“内联”。我担心的是,由于存储在寄存器中,因此跨线程共享的变量变量(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
答案 0 :(得分:6)
是的,它会正常工作。在这里阅读
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生成一个 全围栏;
答案 1 :(得分:4)
我认为你的代码会起作用 - 即使它们只是堆栈变量,闭包也会提升到堆中(ManualReseetEvent肯定不会)。
但是为什么不把所有东西放在event.WaitOne()之后只是在continuation中(块是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的情况下测试这段代码,但是我应该通过错误的拼写/输入来模拟语法错误