public void Enqueue(IoTask task) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } IoTask last = _last, newLast; while (last != null && !ReferenceEquals(last, newLast = Interlocked.CompareExchange(ref _last, task, last))) { last = newLast; } if (last == null) { throw new IOException(); } IoTask prev = Interlocked.Exchange(ref last.Next, task); if (prev != null) { throw new IOException(); } _wakeup.Set(); }
public WorkerState(Stream output, bool closeStream) { _output = output; _closeStream = closeStream; _first = _last = new IoTask(); _wakeup = new ManualResetEvent(false); _stop = new ManualResetEvent(false); _worker = new Thread(WriterThread); _worker.IsBackground = true; _worker.SetApartmentState(ApartmentState.MTA); _worker.Name = GetType().Name; _worker.Start(); }
/// <summary> /// Returns a number of bytes up to length that is pending a write at the position specified and /// copies those bytes into buffer the offset provided. /// </summary> public int Read(long position, byte[] buffer, int offset, int length) { IoTask work = _state.First(); int bytesFound = 0; while (work != null) { if (work.Position == position) { Buffer.BlockCopy(work.Bytes, work.Offset, buffer, offset, bytesFound = Math.Min(length, work.Length)); } work = work.Next; } return(bytesFound); }
void WriterThread() { try { byte[] buffer = new byte[8192]; WaitHandle[] waits = new WaitHandle[] { _stop, _wakeup }; while (true) { int result = WaitHandle.WaitAny(waits); _wakeup.Reset(); while (PerformWrite(ref buffer)) { } if (result != 1) { break; } } _output.Flush(); // Console.WriteLine("Thread {0} write lag = {1}", Thread.CurrentThread.ManagedThreadId, _lagging); Debug.Write( String.Format("Thread {0} write lag = {1}", Thread.CurrentThread.ManagedThreadId, _lagging), GetType().Name ); } catch (ThreadAbortException) { throw; } catch { _first = null; Interlocked.Exchange(ref _last, null); } finally { if (_closeStream) { _output.Close(); } } }
public void Enqueue(IoTask task) { if (_disposed) throw new ObjectDisposedException(GetType().FullName); IoTask last = _last, newLast; while (last != null && !ReferenceEquals(last, newLast = Interlocked.CompareExchange(ref _last, task, last))) last = newLast; if (last == null) throw new IOException(); IoTask prev = Interlocked.Exchange(ref last.Next, task); if (prev != null) throw new IOException(); _wakeup.Set(); }
private bool PerformWrite(ref byte[] buffer) { IoTask start = _first; IoTask next = Interlocked.CompareExchange(ref start.Next, null, null); if (next == null) return false;//nothing to do, _first has always been processed IoTask stop = start = next; bool hasSignals = start.Signal != null; int byteLen = stop.Length; long startpos = stop.Position; long position = stop.Position + byteLen; while (null != (next = Interlocked.CompareExchange(ref start.Next, null, null))) { //see if both are append-only (position < 0) if (startpos < 0 && next.Position >= 0) break; //see if the next write immediately follows this if (startpos >= 0 && next.Position != position) break; //see if this write will overflow our max memory buffer limit if (next.Length + byteLen > MemoryLimit) break; if (next.IoAction != null) break; byteLen += next.Length; position += next.Length; hasSignals |= next.Signal != null; stop = next; } if (start.IoAction != null) { start.IoAction(_output); start.IoAction = null; } else if (ReferenceEquals(start, stop)) { if (startpos >= 0) _output.Position = startpos; _output.Write(start.Bytes, start.Offset, start.Length); } else //buffer and write multiple items... { if (buffer.Length < byteLen) Array.Resize(ref buffer, byteLen + 8192); int counter = 0; int offset = 0; IoTask current = start; while (true) { counter++; Buffer.BlockCopy(current.Bytes, current.Offset, buffer, offset, current.Length); offset += current.Length; if (ReferenceEquals(current, stop)) break; current = current.Next; } _lagging = Math.Max(_lagging, counter); if (startpos >= 0) _output.Position = startpos; _output.Write(buffer, 0, offset); } while (hasSignals) { if (start.Signal != null) { start.Signal.Set(); start.Signal = null; } if (ReferenceEquals(start, stop)) break; start = start.Next; } _first = stop; return true; }
void WriterThread() { try { byte[] buffer = new byte[8192]; WaitHandle[] waits = new WaitHandle[] { _stop, _wakeup }; while (true) { int result = WaitHandle.WaitAny(waits); _wakeup.Reset(); while (PerformWrite(ref buffer)) { } if (result != 1) break; } _output.Flush(); // Console.WriteLine("Thread {0} write lag = {1}", Thread.CurrentThread.ManagedThreadId, _lagging); Debug.Write( String.Format("Thread {0} write lag = {1}", Thread.CurrentThread.ManagedThreadId, _lagging), GetType().Name ); } catch (ThreadAbortException) { throw; } catch { _first = null; Interlocked.Exchange(ref _last, null); } finally { if (_closeStream) _output.Close(); } }
private bool PerformWrite(ref byte[] buffer) { IoTask start = _first; IoTask next = Interlocked.CompareExchange(ref start.Next, null, null); if (next == null) { return(false);//nothing to do, _first has always been processed } IoTask stop = start = next; bool hasSignals = start.Signal != null; int byteLen = stop.Length; long startpos = stop.Position; long position = stop.Position + byteLen; while (null != (next = Interlocked.CompareExchange(ref start.Next, null, null))) { //see if both are append-only (position < 0) if (startpos < 0 && next.Position >= 0) { break; } //see if the next write immediately follows this if (startpos >= 0 && next.Position != position) { break; } //see if this write will overflow our max memory buffer limit if (next.Length + byteLen > MemoryLimit) { break; } if (next.IoAction != null) { break; } byteLen += next.Length; position += next.Length; hasSignals |= next.Signal != null; stop = next; } if (start.IoAction != null) { start.IoAction(_output); start.IoAction = null; } else if (ReferenceEquals(start, stop)) { if (startpos >= 0) { _output.Position = startpos; } _output.Write(start.Bytes, start.Offset, start.Length); } else //buffer and write multiple items... { if (buffer.Length < byteLen) { Array.Resize(ref buffer, byteLen + 8192); } int counter = 0; int offset = 0; IoTask current = start; while (true) { counter++; Buffer.BlockCopy(current.Bytes, current.Offset, buffer, offset, current.Length); offset += current.Length; if (ReferenceEquals(current, stop)) { break; } current = current.Next; } _lagging = Math.Max(_lagging, counter); if (startpos >= 0) { _output.Position = startpos; } _output.Write(buffer, 0, offset); } while (hasSignals) { if (start.Signal != null) { start.Signal.Set(); start.Signal = null; } if (ReferenceEquals(start, stop)) { break; } start = start.Next; } _first = stop; return(true); }