C# 在两个线程之间传递数据时,如何确保线程看到最新的值?

C# 在两个线程之间传递数据时,如何确保线程看到最新的值?,c#,multithreading,pinvoke,C#,Multithreading,Pinvoke,我通过PInvoke调用使用本机库,该调用返回字节*,并希望确保在生产者/消费者场景中,消费者线程获取最新数据 我这里有一个非常做作的例子,试图说明我的问题。我知道消费者中存在“热循环”(这只是一个例子,实际代码要大得多,粘贴在这里是不可行的) 公共不安全类线程示例{ PInvokeResult类{ 公共字节*数据; 公共Int32长度; } //用于同步的共享对象 对象SyncRoot=新对象(); 队列工作队列=新队列(); //生产者线程 无效生产者(){ while(true){ PIn

我通过PInvoke调用使用本机库,该调用返回字节*,并希望确保在生产者/消费者场景中,消费者线程获取最新数据

我这里有一个非常做作的例子,试图说明我的问题。我知道
消费者
中存在“热循环”(这只是一个例子,实际代码要大得多,粘贴在这里是不可行的)

公共不安全类线程示例{
PInvokeResult类{
公共字节*数据;
公共Int32长度;
}
//用于同步的共享对象
对象SyncRoot=新对象();
队列工作队列=新队列();
//生产者线程
无效生产者(){
while(true){
PInvokeResult工作项目;
workItem=新的PInvokeResult();
workItem.Data=PInvokeNativeLongRunningCall(out workItem.Length);
锁定(同步根){
WorkQueue.Enqueue(workItem);
}
}
}
//消耗线程
无效消费者(){
while(true){
bool workAvailable=false;
PInvokeResult workItem=null;
锁定(同步根){
如果(WorkQueue.Count>0){
workItem=WorkQueue.Dequeue();
workAvailable=true;
}
}
如果(可用){
进程工作项(工作项);
PInvokeReturnPointerBuffer(工作项数据);
}
}
}
}
这里的锁是否足以确保从PInvokeResult上的
字节*
指针读取的数据不会指向消费者的“过时”数据

我这里所说的陈旧数据是指以下情况:

  • PInvokeNativeLongRunningCall
    调用返回一个特定字节*缓冲区
  • 缓冲区从生产者传递到消费者,这使用对SyncRoot的锁定来确保对队列的访问是安全的
  • 消费者对商品进行一些处理,然后通过
    PInvokeReturnPointerBuffer将其返回到本机代码
  • 然后在本机端回收并重新使用缓冲区,缓冲区中的数据首先设置为全零,然后再次写入
  • 然后循环从
    1开始。
  • 当第二次缓冲区到达消费者时,我如何确保它看到的数据是PInvoke调用写入的最新数据

    这个问题纯粹是从C#的角度来看的,我知道本机代码很好而且很可靠,它是一个使用良好的库


    这是一种语言必须考虑的问题,还是完全由CPU自己处理

    是的,锁够了。你可以免费获得它使用的内存屏障。即使我害怕的数据“过时”是来自正在运行的应用程序的本机部分?我认为这并不重要,CPU不关心正在执行的语言类型,等等。对,处理器只知道一种数据。
    public unsafe class ThreadExample {
      class PInvokeResult {
        public Byte* Data;
        public Int32 Length;
      }
    
      // Shared Objects Used For Synchronization
      Object SyncRoot = new Object();
      Queue<PInvokeResult> WorkQueue = new Queue<PInvokeResult>();
    
      // Producer Thread
      void Producer() {
        while (true) {
          PInvokeResult workItem;
          workItem = new PInvokeResult();
          workItem.Data = PInvokeNativeLongRunningCall(out workItem.Length);
    
          lock (SyncRoot) {
            WorkQueue.Enqueue(workItem);
          }
        }
      }
    
      // Consume Thread
      void Consumer() {
        while (true) {
          bool workAvailable = false;
          PInvokeResult workItem = null;
    
          lock (SyncRoot) {
            if (WorkQueue.Count > 0) {
              workItem = WorkQueue.Dequeue();
              workAvailable = true;
            }
          }
    
          if (workAvailable) {
            ProcessWorkItem(workItem);
            PInvokeReturnPointerBuffer(workItem.Data);
          }
        }
      }
    }