C# NET中共享变量的线程池管理

C# NET中共享变量的线程池管理,c#,.net,multithreading,threadpool,C#,.net,Multithreading,Threadpool,假设我有一个计时器(例如System.Timers.timer),我们知道每个elasped事件都会被放入线程池。如果事件发生得足够快,线程池如何管理对共享变量(例如,全局int计数器)的访问。经理是否在发动机罩下使用信号灯/锁 或者它什么都不做,只是在线程池的开始处复制共享变量,最后一个要完成的线程将设置正确的变量值 不幸的是,我无法真正测试这一点,因为在每个经过的事件之间不能保证事件触发的顺序(例如,使用计数器变量是不可靠的),因为它们可能会无序触发 谢谢您必须自己管理对共享变量的多线程访问

假设我有一个计时器(例如System.Timers.timer),我们知道每个elasped事件都会被放入线程池。如果事件发生得足够快,线程池如何管理对共享变量(例如,全局int计数器)的访问。经理是否在发动机罩下使用信号灯/锁

或者它什么都不做,只是在线程池的开始处复制共享变量,最后一个要完成的线程将设置正确的变量值

不幸的是,我无法真正测试这一点,因为在每个经过的事件之间不能保证事件触发的顺序(例如,使用计数器变量是不可靠的),因为它们可能会无序触发


谢谢

您必须自己管理对共享变量的多线程访问

在StackOverflow和Google上有很多答案解释了如何做到这一点,搜索“线程安全C”

我在大型项目中工作过,有很多潜在的线程问题,我写的代码很管用。这些天我非常擅长编写线程安全代码,因为我已经犯了所有可能的错误

如果您只是在学习编写线程安全代码,那么很容易被大量信息淹没。你可能会发现一些页面。你会发现关于这个话题的大量讨论,其中只有一半会有帮助

如果您是第一次遵循学习曲线,我建议您暂时忽略上述噪音,而是首先专注于掌握这两条规则:

规则1 如果任意两个线程写入某个共享原语(如
long
字典
列表
),请在访问此共享原语的周围放置一个
。针对这样一种情况,当锁定完成时,数据结构将完全更新。这是编写线程安全代码的核心:所有其他线程规则都可以由此派生

示例:

// This _lock should be initialized once on program startup, and should be global.
static readonly object _dictLock = new object();    

// This data structure can be accessed by multiple threads.
public static Dictionary<string, int> dict = new Dictionary<string, int>();

lock (_dictLock)
{
    if (dict.ContainsKey("Hello") == false)
    {
        dict.Add("Hello", 42);
    }
} // Lock exits: data structure is now completely 100% updated. Google "atomic access C#".
//这个_锁应该在程序启动时初始化一次,并且应该是全局的。
静态只读对象_dictLock=新对象();
//此数据结构可由多个线程访问。
公共静态字典dict=新字典();
锁
{
if(dict.ContainsKey(“Hello”)==false)
{
dict.Add(“你好”,42);
}
}//锁退出:数据结构现在完全100%更新。谷歌“原子访问C”。
规则2 尽量不要在锁中有锁。如果以错误的顺序输入锁,则会造成死锁。如果只锁定原语(例如,
字典
字符串
,等等),那么这应该不是问题

准则1 如果您只是在学习,请只使用
锁定
,请参阅。如果只是这样,很难出错,因为当函数退出时,锁会自动释放。稍后,您可以升级到其他类型的锁,如读写锁。不要为
ConcurrentDictionary
Interlocated(互锁)而烦恼。增加
但-专注于获得正确的基础知识

准则2 尽量少花时间在锁上。不要在一大块代码上加锁,要在代码中可能最小的部分上加锁,通常是
字典
。锁的速度非常快,除非它有争议,所以这种技术似乎可以很好地创建快速的线程安全代码

95%有意义的线程问题的原因?
根据我的经验,线程不安全代码的一个最大原因是
Dictionary
。即使是
ConcurrentDictionary
也无法避免这种情况-如果访问跨越多行,则需要手动锁定才能正确。如果你做到了这一点,你将消除代码中95%有意义的线程问题。

线程池无法神奇地使共享可变变量线程安全。它无法控制它们,甚至不知道它们的存在

请注意,计时器滴答声可以同时发生(即使在低频率下)并且在计时器被释放后发生。您需要执行任何必要的同步


线程池本身是线程安全的,因为我可以成功地处理并发的工作项(这是一个要点)。

这应该是一个注释,否则您需要提供必要的链接和相关细节。我在回答的第一部分写道,当我进入地铁时,手机上的信号丢失了,所以无法写下剩下的内容。我想最好早点点击
Submit
,因为有些信息总比什么都没有好。+1现在,相关细节更为合理,尽管使用给定机制进行同步在很大程度上取决于完成的工作类型,我更喜欢.Net 4.0并发数据结构。它们有多个同步机制,防止多个线程写入共享变量。它将在内部使用其中一个,不确定它是否是锁、信号量,对于整数它可能是互锁的