繁体   English   中英

在线程之间共享局部变量是否安全(通过回调闭包)?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM