C#One Writer很多读者都读过一次

我有4个帖子.一个是从网络中读取一些信息,将其写入变量,并在每个部分后发出信号.其中3个正在阅读这个变量,应该只读一次.当前的解决方案是编写器在写入并等待读者事件之后设置事件.读者等待事件,然后阅读并设置他们的事件(意思是他们阅读).问题是读者可以阅读不止一次,我有重复.如何才能让读者完全阅读一次?

解决方法:

实现此目的的一种方法如下

数据在线程之间作为单链表共享.列表中的每个节点都可以是标记或具有数据.该列表以单个节点开始,该节点键入到标记.当读取数据时,形成新的列表,其具有一系列数据节点,后跟标记.此列表将附加到添加到列表中的最新标记.

每个读者线程都以对原始标记节点和AutoResetEvent的引用开始.每当新的数据进入编写器时,它将为每个读取器线程发出AutoResetEvent信号.然后读者线程将简单地走,直到找到没有Next节点的标记.

该方案确保所有读者只能看到一次数据.最大的复杂因素是构建列表,以便可以以无锁方式写入和读取.尽管如此,Interlocked.CompareExchange非常简单

链接列表类型

class Node<T> { 
  public bool IsMarker;
  public T Data;
  public Node<T> Next;
}

样本编写者类型

class Writer<T> {
  private List<AutoResetEvent> m_list; 
  private Node<T> m_lastMarker;

  public Writer(List<AutoResetEvent> list, Node<T> marker) { 
    m_lastMarker = marker;
    m_list = list;
  }

  // Assuming this can't overlap.  If this can overload then you will
  // need synchronization in this method around the writing of 
  // m_lastMarker      
  void OnDataRead(T[] items) {
    if (items.Length == 0) {
      return;
    }

    // Build up a linked list of the new data followed by a 
    // Marker to signify the end of the data.  
    var head = new Node<T>() { Data = items[0] };
    var current = head;
    for (int i = 1; i < items.Length; i++) {
      current.Next = new Node<T>{ Data = items[i] };
      current = current.Next;
    }
    var marker = new Node<T> { IsMarker = true };
    current.Next = marker;

    // Append the list to the end of the last marker node the writer
    // created 
    m_lastMarker.Next = head;
    m_lastMarker = marker;

    // Tell each of the readers that there is new data 
    foreach (var e in m_list) { 
      e.Set();
    }
  }
}

样本读者类型

class Reader<T> { 
  private AutoResetEvent m_event;
  private Node<T> m_marker;

  void Go() {
    while(true) { 
      m_event.WaitOne();
      var current = m_marker.Next;
      while (current != null) { 
        if (current.IsMarker) { 
          // Found a new marker.  Always record the marker because it may 
          // be the last marker in the chain 
          m_marker = current;
        } else { 
          // Actually process the data 
          ProcessData(current.Data);
        }
        current = current.Next;
      }
    }
  }
}
上一篇:关于Java中的同步方法


下一篇:java同步中条件变量和条件谓词之间的区别