今天我偶然发现了一个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调用之前设置的数据不匹配。
通常,我尝试以最高效的方式在线程之间进行数据传输。 使用这种方法(没有锁)是否合适或是否有更多可接受的方法?
答案 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)
从我在方法Exchange和CompareExchange的引用中所读到的,它们并不意味着存在内存障碍。因此,将值写入data[index]
可以与dataStates[index]
的互锁设置交换,这意味着第二个线程可能实际读取无效数据。
我同意sprinter252可能有更好的方法来实现它。这不是正常的producer-consumer problem吗?这可以用信号量解决,也可以像sprinter的答案那样重写为使用任务队列。