C#(.NET,Mono)使用数组在线程之间传输数据

问题描述 投票:0回答:2

今天我不小心偶然发现了一个MemoryBarrier并意识到我并不完全理解带RAM的CPU的工作。搜索没有给我一个明确的答案,所以我决定提出一个新问题。

有两个数组:

int[] dataStates; //default items value is 0
MyStruct[] data; //MyStruct is a struct with several fields

有两个线程(ThreadS,ThreadS)

ThreadA执行以下代码:

data[index] = ... //new value
//change to "1" after setting data
Interlocked.Exchange(ref dataStates[index], 1);

ThreadB代码:

//wait for "1" in array item and replace to "2"
while(Interlocked.CompareExchange(ref dataStates[index], 2, 1) != 1)
{
     Thread.Sleep(0);
}

//read actual data
var value = data[index];

线程是否可能从数据[索引]中读取数据并且它们将被淘汰?通过“过时”这个词,我的意思是从阵列接收的数据与Interlocked.Exchange调用之前设置的数据不匹配。

一般来说,我尝试以最有效的方式在线程之间进行数据传输。使用这种方法(没有锁)是否合适或是否有更多可接受的方法?

c# .net multithreading memory mono
2个回答
0
投票

我不知道这是否是解决方案,但据我了解您的样本,您可以执行以下操作:

var queue = new ConcurrentQueue<DateTime>();
var tcs = new CancellationTokenSource();
var token = tcs.Token;
Task.Run(async () => {
    for (var i = 0; i < 2; i++) 
    {
        queue.Enqueue(DateTime.Now);
        await Task.Delay(2000);
    }
    tcs.Cancel();
}, token);
Task.Run(() => {
    while (!token.IsCancellationRequested) 
    {
        if (queue.Any())
        {
            DateTime result;
            queue.TryDequeue(out result);
            Console.WriteLine($"Received {result}...");
        }
    }
}, token).ContinueWith(t =>
{
    Console.WriteLine("Stop");
});
Console.ReadLine();
tcs.Cancel();

您将需要一些命名空间导入:

using System.Threading;
using System.Threading.Tasks
using System.Collections.Concurrent;

这是一个完全不同的apporach avodiding线程之间的手动同步。我使用DateTime而不是MyStruct


0
投票

从我在参考方法ExchangeCompareExchange中所读到的,它们并不意味着记忆障碍。因此,将值写入data[index]可以与dataStates[index]的互锁设置交换,这意味着第二个线程可能实际读取无效数据。

我同意sprinter252,可能有更好的方法来实现它。这不是一个正常的producer-consumer problem?这可以用信号量解决,或者可以重写为使用任务队列,就像在短跑运动员的答案中一样。

© www.soinside.com 2019 - 2024. All rights reserved.