静态变量和多线程

时间:2013-12-17 09:31:46

标签: c# .net

将静态变量作为计数器是一个好习惯,可以由C#.NET程序中的所有线程更新吗?
示例代码:

public class SomeTask 
{
static int count = 0;
public void Process()
{

    while(true)
    {
        //some repeated task
        count++;
        if(count>100000)
        {
            count=0;
            break;
        }
    }
}
}

public class WorkerRole : RoleEntryPoint
{
   public override void Run()
    {
    while(true)
    {

        for (int i = 0; i < maxTasks; i++)
        {
            this.Tasks[i] = Task.Factory.StartNew(() => (new SomeTask()).Process());
        }
        Task.WaitAll(this.Tasks);

        //every 100000 in counter needs some updates at program level
    }
}
}

3 个答案:

答案 0 :(得分:2)

是的,这是一个很好的方法,但要确保使用原子类型。如果使用线程安全代码而不是原子操作来实现计数器增量操作,我会遇到性能问题。

要实施计数器,您将使用++--。通常,这些对C#中的原始类型不是线程安全的。

请参阅Is the ++ operator thread safe?

C#中的原子类型?

参见参考What operations are atomic in C#?

这个答案表明32位机器上32位整数类型是原子的,64位机器上64位整数类型是原子类型。

答案 1 :(得分:2)

如果你无法避免,那就没事了。最好使用Interlocked class递增计数器:

if (Interlocked.Increment(ref counter) % 100000 == 0) {
    // Do something every hundred thousand times
    // Use "== 1" if you also want to do it on the first iteration
}

如果您只需要知道最后的计数,我会留下以下代码

在您的情况下,您可以将count保留为实例字段(即非静态),添加公共getter并在所有任务完成后汇总所有计数器:

public class SomeTask 
{
    int count = 0;
    public int Count { get { return count; } }

    public void Process()
    {

        while(true)
        {
            //some repeated task
            count++;

            if (something)
                break;
        }
    }        
}

var someTasks = new List<SomeTask>();
for (int i = 0; i < maxTasks; i++)
{
    var someTask = new SomeTask();
    someTasks.Add(someTask);
    this.Tasks[i] = Task.Factory.StartNew(() => someTask.Process());
}
Task.WaitAll(this.Tasks);

// Your total count
var total = someTasks.Sum(t => t.Counter);

答案 2 :(得分:0)

,只要您保持thread-safe并在线程中同步,它就完全可以了。您可以使用lock进行同步。您可以阅读有关线程安全性和静态成员herehere的更多信息。您还可以使用Interlocked.Increment以线程安全的方式增加计数器。在Eric Lippert answer中通过增量运算符了解有关线程安全的更多信息。

class Account
{
    int count;
    private Object thisLock = new Object();

    public void Add(decimal amount)
    {
        //your code
        lock (thisLock)
        {
           count = count + 1;
        }
    }
}