Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在Parallel.For内修改的方法局部变量。这个线程有多安全?_C#_Multithreading_Thread Safety_Task Parallel Library_Parallel.foreach - Fatal编程技术网

C# 正在Parallel.For内修改的方法局部变量。这个线程有多安全?

C# 正在Parallel.For内修改的方法局部变量。这个线程有多安全?,c#,multithreading,thread-safety,task-parallel-library,parallel.foreach,C#,Multithreading,Thread Safety,Task Parallel Library,Parallel.foreach,我有以下代码片段: int totalData = result.Data.Count; int count = 0; Parallel.ForEach(result.Data, data => { try { EventRange importedEntity = ImportEntity(auxResult.EntityName, data); count++; EntityImported(importedEntity,

我有以下代码片段:

int totalData = result.Data.Count;
int count = 0;
Parallel.ForEach(result.Data, data =>
{
    try
    {
        EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
        count++;
        EntityImported(importedEntity, count, totalData);
    }
    catch (Exception e)
    {
        exceptions.Enqueue(e);
    }
});

EntityImported是一个事件,它应该说明已经处理了多少实体,以及我应该处理多少实体。我担心的是lambda中递增count的线程安全性,以及您建议采取哪些步骤来确保总是使用正确的count变量值触发事件。

目前,它根本不是线程安全的

您可以使用
Interlocked.Increment(ref count)
来代替,但通常最好为每个线程设置一个“local”值,并在最后求和。这样,除了分配要处理的项之外,您不需要任何类型的跨线程数据流

这里有一个为这个目的而设计的重载—请看文档底部附近的示例,因为它所做的事情与您的代码非常相似。(它维护一个局部计数,然后在最后对计数求和。)不幸的是,这对您的特定情况没有帮助,因为您需要在每次迭代中引发事件的方式——但通常这是一种更好的方法

在这种情况下,您应该在事件引发代码中使用
Interlocked.Increment
的结果:

Parallel.ForEach(result.Data, data =>
{
    try
    {
        EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
        int newCount = Interlocked.Increment(ref count);
        EntityImported(importedEntity, newCount, totalData);
    }
    catch (Exception e)
    {
        exceptions.Enqueue(e);
    }
});

这样,每次计数将只引发一个事件(一个为0,一个为1,一个为2等)。

谢谢Jon,尽管我不确定我是否理解该重载如何帮助我。如果我理解正确,它允许我将某个值传递给lambda,以正常方式求和,然后使用它执行最终操作,以最小化必要的联锁操作量。如果我需要用处理过的实体的总量进行操作,它将为我服务。然而,我的问题是,我需要在处理每个实体时,用当前处理的实体数量引发一个事件。我是不是误会了什么,或者超载对我没有好处?@Uri:啊,我错过了。在这种情况下,请退回到使用Interlocked.Increment。@Uri:在Interlocked.Increment和调用EntityImported之间,count可能已经更改。优化器可能会针对该值优化返回内存的输出,但可能不会。它可能没有那么快,但您可能希望在lambda中创建一个局部变量,在递增count之前锁定,然后复制count local。eg=>importedEntity=blah();内部计数;lock(lock_object){interlocked.inc(count);internalcount=count;}EntityImported(count,importedEntity)@本吉:比赛是一个很好的观点,但没有必要使用锁定。只需使用
Interlocked.Increment的返回值即可。有关示例代码,请参阅我编辑过的答案。@JonSkeet:我刚刚学到了一些新的,Interlocked.Increment返回值。谢谢