c# - С# SemaphoreSlim 保证什么?它是完整的内存屏障吗?我们可以确定两个不同的信号量 Wait() 和 Release() 之间的代码是什么?
问题描述
С# SemaphoreSlim 保证什么?它是完整的内存屏障吗?我们可以确定两个不同的信号量 Wait() 和 Release() 之间的代码是什么?执行不同 SemaphoreSlim Wait()、Release() 和 Interlocked 方法和 Volatile 的序列。写/读总是在每个线程中保持顺序?
public T Dequeue()
{
canReadCountSemaphoreSlim.Wait();
int i = Interlocked.Decrement(ref end);
T val = Volatile.Read(ref buf[i]);
canWriteCountSemaphoreSlim.Release();
return val;
}
public void Enqueue(T val)
{
canWriteCountSemaphoreSlim.Wait();
int i = Interlocked.Decrement(ref start);
Volatile.Write(ref buf[i], val);
canReadCountSemaphoreSlim.Release();
}
完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
namespace Program
{
public class BlockingRingQueue<T> where T: class
{
const int BUFSIZE_LOG2 = 10;
const int BUFSIZE = 1 << BUFSIZE_LOG2;
T[] buf = new T[BUFSIZE];
int start = 0;
int end = 0;
SemaphoreSlim canReadCountSemaphoreSlim = new SemaphoreSlim(0);
SemaphoreSlim canWriteCountSemaphoreSlim = new SemaphoreSlim(BUFSIZE);
public T Dequeue()
{
canReadCountSemaphoreSlim.Wait();
int i = Interlocked.Decrement(ref end);
i = PositiveMod(i, BUFSIZE);
T val = Volatile.Read(ref buf[i]);
canWriteCountSemaphoreSlim.Release();
return val;
}
public void Enqueue(T val)
{
canWriteCountSemaphoreSlim.Wait();
int i = Interlocked.Decrement(ref start);
i = PositiveMod(i, BUFSIZE);
Volatile.Write(ref buf[i], val);
canReadCountSemaphoreSlim.Release();
}
static int PositiveMod(int a, int b) => ((a % b) + b) % b;
}
public class Program
{
const int READ_THREAD_COUNT = 3;
static BlockingRingQueue<string> queue = new BlockingRingQueue<string>();
public static void Main(string[] args)
{
new Thread(() => Pushing("ABCD")) { Name = "0" }.Start();
for(int i = 1; i <= READ_THREAD_COUNT; i++)
new Thread(Poping) { Name = i.ToString() }.Start();
}
public static void Poping()
{
while(true)
{
RandSpinWait();
var val = queue.Dequeue();
if("" == val)
break;
Console.WriteLine(val + Thread.CurrentThread.Name + ' ');
}
//Console.WriteLine('!' + Thread.CurrentThread.Name + ' ');
}
public static void Pushing(string chars)
{
RandSpinWait();
var vals = chars.ToCharArray().Select(c => $"{c}")
.Concat(Enumerable.Repeat("",READ_THREAD_COUNT));
foreach(string v in vals)
queue.Enqueue(v);
}
public static void RandSpinWait() => Thread.SpinWait(new Random().Next(1));
}
}
解决方案
推荐阅读
- python - NetworkX最小生成树对于相同的数据有不同的集群排列?
- java - 顶级类和类成员的访问修饰符
- terraform - 在 terraform 中使用 End of text string(EOT) 添加长内容会引发错误
- python - 从字典中获取样本
- php - WordPress 和 CodeIgniter htaccess
- pytorch - 使用torchvision.ops.roi_align 时,出现错误:进程以退出代码139 完成(被信号11 中断:SIGSEGV)
- python - DGM 网络中的“每个样本的步数”
- c# - C# 方法在 Enter 键上被调用两次
- flutter - 为什么“base is derivedA || base is derivedB”不能按预期工作?
- c++ - 如何修改我的 Qt PaintEvent 代码以相对于鼠标指针缩放显示的像素图