C ++ \ Cli Interlocked :: Add for doubles-无法获得Interlocked :: CompareExchange替代方法

jdelange

这是先前问题的后续解决方案,该问题解决了带有线程局部变量的Parallel :: For语法带有局部变量的Parallel :: For

我尝试实现的书籍示例在整数上执行了Interlocked :: Add,但是我的实现需要加倍。在上面引用的代码中,我实现了Lock例程,但这不起作用。因此,我现在尝试将C#示例转换为C ++ \ Cli类,然后我可以将其作为安全加倍Doubles Interlocked.CompareExchange进行调用。

TreadSafe.h

using namespace System;
using namespace System::Threading;

ref class ThreadSafe
{
private:
    double totalValue;

public:
    property double Total
    {
        double get()
        {
            return totalValue;
        }
    }
    double AddToTotal(double addend);

    // constructor
    ThreadSafe(void);
};

ThreadSafe.cpp

// constructor
ThreadSafe::ThreadSafe(void)
{
    totalValue = 0.0;
}

double ThreadSafe::AddToTotal(double addend)
{
    double initialValue, computedValue;
    do
    {
        initialValue = totalValue;
        computedValue = initialValue + addend;
    }
    while (initialValue != Interlocked::CompareExchange(totalValue, computedValue, initialValue));

    return computedValue;
}

然后,我在包含Parallel:For例程的类中进行调用,该例程也在上面引用的文章中列出。

DataCollection.cpp

// constructor
DataCollection::DataCollection(Form1^ f1) // takes parameter of type Form1 to give acces to variables on Form1
{
    this->f1 = f1;

    ts = gcnew ThreadSafe();
}

// initialize data set for parallel processing
void DataCollection::initNumbers(int cIdx, int gIdx)
{
    DataStructure^ number;
    numbers = gcnew List<DataStructure^>();

    for (int i = 0; i < f1->myGenome->nGenes; i++)
    {
// creates collection "numbers" with data to be processed in parallel
    }
}

// parallel-for summation of scores
double DataCollection::sumScore()
{
    Parallel::For<double>(0, numbers->Count, gcnew Func<double>(this, &DataCollection::initSumScore),
                                                gcnew Func<int, ParallelLoopState^, double, double>(this, &DataCollection::computeSumScore),
                                                gcnew Action<double>(this, &DataCollection::finalizeSumScore));
    return ts->Total;
}

// returns start value
double DataCollection::initSumScore()
{
    return 0.0;
}

// perform sequence alignment calculation
double DataCollection::computeSumScore(int k, ParallelLoopState^ status, double tempVal)
{
// calls several external methods, but for testing simplified to an assignment only

    tempVal += 1.0;

    return tempVal;
}

// locked addition
void DataCollection::finalizeSumScore(double tempVal)
{
    ts->AddToTotal(tempVal);
}

该代码可以编译并运行,但不会添加。它总是返回0。

因此,我假设我对C#示例的翻译/实现不正确。怎么了?

乔尔·朗多(Joel Rondeau)

我使用您的ThreadSafe做了一个非常简单的例子

ref class foo
{
public:
  ThreadSafe^ ts;
  foo() {ts = gcnew ThreadSafe();}
  double init() { return 0.0; }
  double add(int i, ParallelLoopState^, double d) { return d + 1.0; }
  void end(double d) { ts->AddToTotal(d); }
};

int main(array<System::String^>^args)
{
  foo^ f = gcnew foo();
  Parallel::For<double>(0,1000000,
    gcnew Func<double>(f, &foo::init),
    gcnew Func<int, ParallelLoopState^, double, double>(f, &foo::add),
    gcnew Action<double>(f, &f::end));
  Console::WriteLine(f->ts->Total);
}

我已经看到它运行有1、2和4个任务线程。始终输出1000000(在这种情况下)。

可以肯定的是,您在ThreadSafe课堂上没有犯错我会开始在别处寻找。

编写代码后,numbers->Count等于0,这将导致Parallel::For永不执行。我假设您只是省略了填充的代码numbers,但是如果没有,那将是它无法正常工作的原因之一。

更新:这是我打算在Parallel:For循环中执行的操作的解释
每个任务都从0开始。每次调用都会Add增加1任务的运行量,然后,一旦任务完成,它将其总数写到ThreadSafe类中。

因此,我没有为AddToTotal每个任务调用100次,而是为每个任务调用了一次:

  • 1个任务:调用值为100的AddToTotal。
  • 2个任务:用大约50的2个值调用AddToTotal,总和为100。
  • 4个任务:用大约25的4个值调用AddToTotal,总计为100。

我的add()函数仍然是线程安全的,因为它不访问input参数以外的任何值,input参数d既不是返回值init()(任务启动时),也不是add()该任务的前一个值

为了证明我的观点,我Console::WriteLine(d)end()函数中添加了a并将其计数增加到1000000。我运行了很多次,最终计数始终为1000000。这是一个仍然有效的异常示例:467922、454959、77119。总计1000000。(第一个时间,我已经看过3个任务)。

当然,现在我刚刚想到了您的问题,我只打AddToTotal了几次电话,可能永远不会同时打电话。

这是我对add()和end()的更新:

double add(int i, ParallelLoopState^, double d) { return bar->AddToTotal(1.0); }
void end(double d) { Console::WriteLine(d); }

现在,所有添加都在任务中完成,AddToTotal将被称为1000000次。end()只会输出最后AddToTotal一次调用所返回的每个任务的最终编号add()

我仍然收到1000000个电话。我确实得到了更多的任务,可能是由于到AddToTotal现在为止的所有呼吁

所以我同意。我的第一次尝试并不是AddToTotal线程安全的良好证明现在,我希望是这样。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

可以Interlocked.CompareExchange抛出NullReferenceException吗?

Interlocked.CompareExchange instruction reodering of the initialvalue

如何正确使用 Interlocked.Add()?

Interlocked.CompareExchange 单线程等效代码

如何在Interlocked.CompareExchange中使用数组项

Interlocked.CompareExchange(参考值,newValue,compareTo)

为什么Interlocked.Add()方法必须返回一个值?

Java原子整数和C#Interlocked.Increment方法之间的区别

C#代码优化导致Interlocked.Exchange()问题

C#:使用 Interlocked 计算委托的调用次数是否正确?

Interlocked.CompareExchange指令重新初始化初始值

在.NET中使用Interlocked类进行多线程的正确方法

在 Semaphore WaitOne 之后调用 Interlocked

如何使用Interlocked.Add更新我的模型计数器值

C#ʻInterlocked.Exchange(Object,Object):Object`的Java等效项是什么?

Java与.Net的Interlocked类等效吗?

SQL Server 中的 NEXT VALUE FOR @Sequence 是否与 C# 中的 Interlocked.Increment() 工作方式相同?

除了已在其重载中声明的类型之外,无法Interlocked.Exchange对象

是Interlocked.Increment()在VisualBasic.Net中的表现如此出色

读取由其他线程上的Interlocked更新的int

我应该在这里使用Interlocked.Exchange还是标准写就足够了?

Interlocked.Increment溢出会导致.NET运行时损坏吗?

Interlocked.Exchange() 具有依赖于读取锁定变量的自定义条件

为什么将变量声明为 volatile 并同时对其使用 Interlocked?

C#枚举的替代方法以获得智能优势

无法从C#执行TekRadius CLI

C ++ Cli WebClient无法在dll中工作

Threading.Volatile.Read(Int64)和Threading.Interlocked.Read(Int64)之间的区别?

C ++ / CLI中的List <T>查找方法