在C#中将锁语句与ThreadPool一起使用 [英] Using lock statement with ThreadPool in C#

查看:216
本文介绍了在C#中将锁语句与ThreadPool一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a multi-threaded program (C#) where I have to share global static variables between threads that may take some time to execute (sending data request to another system using WCF). The problem is that using the lock statement does not seem to guarantee mutual exclusion when it's declared outside of the ThreadPool.

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

So the lock does not work and the program can prints: Timer2 var = 1

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

Putting the the lock statement inside the ThreadPool seems to resolve the problem.

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);
        } 
    }));    
}

但是,我不理解两种方法之间的区别以及为什么它不会产生相同的行为.

However, I don't uderstand the difference between the two approaches and why it does not produce the same behaviour.

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

Also, the 2nd approach resolves the mutual exclusion problem but the timer1 thread will always have to wait for the timer2 to finish his lock statement (which takes time), so the multi-threading concept does not work anymore in my program. I want to know what's the best solution of having multi threading doing their job in parallel with using shared variables ?

推荐答案

您不需要锁即可更新此类变量.例如,您可以替换为:

You don't need a lock to update variables like that. For example, you can replace this:

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

具有:

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

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

Writes to primitive types are guaranteed to be atomic, so there's no need to lock here.

现在,如果要增加一个值,可以编写:

Now, if you want to increment a value, you can write:

int val = Interlocked.Increment(ref globalVar);

您还可以添加:

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

同样,这些不需要锁.

检出互锁类.

这篇关于在C#中将锁语句与ThreadPool一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆