gpt4 book ai didi

c# - 在 C# 中将 lock 语句与 ThreadPool 一起使用

转载 作者:行者123 更新时间:2023-11-30 20:55:23 26 4
gpt4 key购买 nike

我有一个多线程程序 (C#),我必须在线程之间共享全局静态变量,这可能需要一些时间来执行(使用 WCF 将数据请求发送到另一个系统)。问题在于,在 ThreadPool 外部声明时,使用 lock 语句似乎不能保证互斥。

static void Main(string[] args)
{
public static int globalVar = 0;
public object locker;

System.Timers.Timer timer1 = new System.Timers.Timer(1000);
timer1.Elapsed += new ElapsedEventHandler(onTimer1ElapsedEvent);
timer1.Interval = 1000;
timer1.Enabled = true;

System.Timers.Timer timer2 = new System.Timers.Timer(500);
timer2.Elapsed += new ElapsedEventHandler(onTimer2ElapsedEvent);
timer2.Interval = 500;
timer2.Enabled = true;
}

public void onTimer1ElapsedEvent(object source, ElapsedEventArgs e)
{
lock (locker) {
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
globalVar = 1;
Console.WriteLine("Timer1 var = {0}", globalVar);
}));
}
}
public void onTimer2ElapsedEvent(object source, ElapsedEventArgs e)
{
lock (locker) {
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
globalVar = 2;
Thread.Sleep(2000); // simulates a WCF request that may take time
Console.WriteLine("Timer2 var = {0}", globalVar);
}));
}
}

所以锁不起作用,程序可以打印:Timer2 var = 1

将 lock 语句放入 ThreadPool 似乎可以解决问题。

public void onTimer1ElapsedEvent(object source, ElapsedEventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
lock (locker) {
globalVar = 1;
Console.WriteLine("Timer1 var = {0}", globalVar);
}
}));
}
public void onTimer2ElapsedEvent(object source, ElapsedEventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
lock (locker) {
globalVar = 2;
Thread.Sleep(2000); // simulates a WCF request that may take time
Console.WriteLine("Timer2 var = {0}", globalVar);
}
}));
}

但是,我不明白这两种方法之间的区别以及为什么它们不会产生相同的行为。

此外,第二种方法解决了互斥问题,但 timer1 线程将始终必须等待 timer2 完成他的锁定语句(这需要时间),因此多线程概念在我的程序中不再适用。我想知道让多线程与使用共享变量并行工作的最佳解决方案是什么?

最佳答案

你不需要锁来更新这样的变量。例如,您可以替换为:

lock (locker)
{
globalVar = 1;
Console.WriteLine("Timer1 var = {0}", globalVar);
}

与:

int val = 1;
globalVar = val;
Console.WriteLine("Timer1 var = {0}", val);

对原始类型的写入保证是原子的,因此无需在此处锁定。

现在,如果你想增加一个值,你可以这样写:

int val = Interlocked.Increment(ref globalVar);

您还可以添加:

int val = Interlocked.Add(ref globalVar, 100);

同样,这些不需要锁。

查看 Interlocked类。

关于c# - 在 C# 中将 lock 语句与 ThreadPool 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18345042/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com