C#(.NET,Mono)使用数组在线程

时间:2018-03-05 16:52:32

标签: c# .net multithreading memory mono

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

有两个阵列:

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

有两个线程(ThreadA,ThreadB)

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];

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

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

我同意sprinter252可能有更好的方法来实现它。这不是正常的producer-consumer problem吗?这可以用信号量解决,也可以像sprinter的答案那样重写为使用任务队列。