protected virtual Node *GetNodeForReading(int timeout) { for (; ;) { int blockIndex = _nodeHeader->ReadStart; Node *node = this[blockIndex]; if (blockIndex == _nodeHeader->WriteEnd) { // No data is available, wait for it if (DataExists.WaitOne(timeout)) { continue; } // Timeout return(null); } #pragma warning disable 0420 // ignore ref to volatile warning - Interlocked API if (Interlocked.CompareExchange(ref _nodeHeader->ReadStart, node->Next, blockIndex) == blockIndex) { return(node); } #pragma warning restore 0420 // Another thread has already acquired this node for reading, try again continue; } }
/// <summary> /// Attempts to reserve a node from the linked-list for reading with the specified timeout /// </summary> /// <param name="timeout">The number of milliseconds to wait if a node is not immediately available for reading.</param> /// <returns>An unsafe pointer to the node if successful, otherwise null</returns> protected virtual Node *GetNodeForReading(int timeout) { if (_node_readpointer == -1) { Interlocked.Exchange(ref _node_readpointer, _nodeHeader->WriteLastIndex); //first read, init _readstart } //need to wait? long lastcounter = 0; Interlocked.Exchange(ref lastcounter, _nodeHeader->WriteLastCounter); if (_node_readcounter == -1) { _node_readcounter = lastcounter;//first read, init counter } if (_node_readcounter > lastcounter) { // No data is available, wait for it if (timeout <= 0) // check value and set default 10 s { timeout = 10000; } DataExists.Reset(); var starttick = Stopwatch.GetTimestamp(); if (!DataExists.WaitOne(timeout)) { return(null); } DiagInfo.waitticks = Stopwatch.GetTimestamp() - starttick; } int blockIndex = _node_readpointer; Node *node = this[blockIndex]; node->ReserveNodeRead(); //set data for next node if (Interlocked.CompareExchange(ref _node_readpointer, node->Next, blockIndex) == blockIndex) { return(node); } throw new Exception("Another thread has already acquired this node for reading!"); }