c# – 如果我确保两个线程永远不会并行运行,我还是要让我的列表变量挥发吗?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 如果我确保两个线程永远不会并行运行,我还是要让我的列表变量挥发吗?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3488字,纯文字阅读大概需要5分钟。
内容图文
想象一下,我有这个代码,我可以在Windows窗体中找到计时器
产生一些线程 – 但我确保只运行一个线程
以下方法(由here的答案之一 – 由马特约翰逊表示):
nb:我们假设现在这种_executing方法有效,我不使用backgroundworker等.
private volatile bool _executing;
private void TimerElapsed(object state)
{
if (_executing)
return;
_executing = true;
if(smth)
{
Thread myThread = new Thread(MainThread1);
myThread.IsBackground = true;
myThread.Start();
}else
{
Thread myThread = new Thread(MainThread2);
myThread.IsBackground = true;
myThread.Start();
}
}
public void MainThread1()
{
try
{
methodWhichAddelementTomyList(); // e.g., inside list.add();
}
finally
{_executing = false;}
}
public void MainThread2()
{
try
{
methodWhichAddelementTomyList(); // e.g., inside list.add();
}
finally
{_executing = false;}
}
现在我也有List实例变量,你可以看到我从MainThread1和MainThread2访问 – 但是由于我上面的逻辑我确保MainThread1和MainThread2永远不会并行运行,我还是要让列表变为volatile吗?我可以遇到问题吗?
与缓存列表变量有关?
编辑:这种方法是否也保护我不会并行运行这些线程? (链接问题中的答案有点不同 – 它运行计时器内的工作 – 所以我想仔细检查).
EDIT2:老实说,下面是否应该在我的列表对象上应用volatile关键字没有共同意见.这种状况让我很困惑.如此记录的答案仍然受到欢迎;否则这还没有完全回答
解决方法:
我会重申你的问题:
If I ensure two threads never run in parallel do I still have to make my list variable
volatile
?
你没有两个线程,你有三个:一个线程启动另外两个线程.那个总是与其他线程并行运行,并且它使用共享标志与它们通信.鉴于这和您发布的代码,不需要将列表标记为volatile.
但是在只有两个线程和两个线程的情况下,这将以某种方式一个接一个地执行而不受第三个的干扰(即,从共享变量读取),使列表volatile变得足以保证两个线程总是看到相同的数据.
对于两个不同时运行以查看处于一致状态的列表(换句话说,最新)的线程,它们总是必须处理驻留在内存中的最新版本.这意味着当线程开始使用列表时,它必须在先前的写入结束后从列表中读取.
这意味着记忆障碍.线程在使用列表之前需要获取屏障,在完成之后需要释放屏障.使用Thread.MemoryBarrier,您无法精确控制障碍的语义,您总是会获得完全障碍(释放和获取,这比我们需要的更强),但最终结果是相同的.
因此,如果您可以保证线程永远不会并行运行,那么C#内存模型可以保证以下工作符合预期:
private List<int> _list;
public void Process() {
try {
Thread.MemoryBarrier(); // Release + acquire. We only need the acquire.
_list.Add(42);
} finally {
Thread.MemoryBarrier(); // Release + acquire. We only need the release.
}
}
请注意list是如何不易变的.因为不需要:所需要的是障碍.
现在问题是,ECMA C# Language Specification说(强调我的):
17.4.3 Volatile fields
A read of a volatile field is called a volatile read. A volatile read has “acquire semantics“; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
A write of a volatile field is called a volatile write. A volatile write has “release semantics“; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.
(感谢R. Martinho Fernandes查找标准中的相关段落!)
换句话说,从易失性字段读取具有与获取屏障相同的语义,并且写入易失性字段具有与释放屏障相同的语义.这意味着在给定前提的情况下,以下代码节与前一个代码节的行为相同:
private volatile List<int> _list;
public void Process() {
try {
// This is an acquire, because we're *reading* from a volatile field.
_list.Add(42);
} finally {
// This is a release, because we're *writing* to a volatile field.
_list = _list;
}
}
这足以保证只要两个线程不并行运行,它们就会始终看到列表处于一致状态.
(1):两个例子都不完全相同,第一个提供更强的保证,但在这种特定情况下不需要这些强有力的保证.
内容总结
以上是互联网集市为您收集整理的c# – 如果我确保两个线程永远不会并行运行,我还是要让我的列表变量挥发吗?全部内容,希望文章能够帮你解决c# – 如果我确保两个线程永远不会并行运行,我还是要让我的列表变量挥发吗?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。