我很好奇在for循环中做一个空的while循环是否安全,为了阻止它继续直到x为真?
例如(更新到下载示例):
string[] links = new string[3] {"http://url.com/download1.rar", "http://url.com/download2.rar", "http://url.com/download3.rar"};
public void download(String link) {
// download link
x = false;
}
然后在某个地方
for (int i; i < links.length; i++) {
download(links[i]);
x = true;
while (x) {
// Do nothing so the for loop basically freezes until download is finished
}
// Do something else or just end it here and continue the loop
}
请注意:这是一个简单的例子,下载与问题完全无关,我只是想帮助你理解这个问题
还是有更好的方法可以做到这一点吗?
编辑:编辑代码以显示我正在思考的更好的例子
答案 0 :(得分:3)
编辑:更新完全改变了问题。
如果您要更新循环中的x
并且未从外部线程更改,则您的程序将锁定并且不会继续,因为您的代码无法访问x = true
,因为它是被while循环阻止。
这会占用100%的CPU在单个核心上执行0个有用的工作,你认为可以吗?此外,如果x
未标记为volitile,即使您更新x
,它也可能永久旋转。
更好的方法是使用某种互斥锁来阻止代码直到你准备好。例如ManualResetEventSlim
。
private ManualResetEventSlim _block = new ManualResetEventSlim();
public void A()
{
for (int i; i < args.length; i++)
{
_block.Wait(); //This code blocks till UnblockA() is called.
// Do something
}
}
public void UnblockA()
{
_block.Set();
}
public void BlockA()
{
_block.Reset();
}
答案 1 :(得分:1)
直接回答你的问题:不,这不是普遍安全的。请参阅这篇关于.NET中线程的优秀文章中的“内存障碍和易失性”一节:http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility
具体做法是:
“我们真的需要锁和障碍吗?
使用没有锁或围栏的共享可写字段会遇到麻烦。关于这个主题有很多误导性的信息 - 包括MSDN文档,该文档指出仅在内存排序较弱的多处理器系统上需要MemoryBarrier,例如采用多个Itanium处理器的系统。我们可以通过以下简短程序证明内存屏障在普通的英特尔酷睿2和奔腾处理器上非常重要。您需要在启用优化且没有调试器的情况下运行它(在Visual Studio中,在解决方案的配置管理器中选择Release Mode,然后在不调试的情况下启动):
static void Main()
{
bool complete = false;
var t = new Thread (() =>
{
bool toggle = false;
while (!complete) toggle = !toggle;
});
t.Start();
Thread.Sleep (1000);
complete = true;
t.Join(); // Blocks indefinitely
}
此程序永远不会终止,因为完整变量缓存在CPU寄存器中。在while循环中插入对Thread.MemoryBarrier的调用(或锁定读取完成)可以修复错误。“
后来:
“实际上,英特尔的X86和X64处理器始终对读取和释放禁用写入 - 无论您是否使用volatile关键字 - 因此如果您使用此关键字对硬件没有影响但是,volatile会对编译器和CLR以及64位AMD和(在更大程度上)Itanium处理器上执行的优化产生影响。这意味着你不能因为你的处理器而放松一下。客户端运行特定类型的CPU。
(即使你确实使用了挥发性物质,你仍应保持健康的焦虑感,我们很快就会看到!)“