void Enqueue(FilePacketArray filePacket) { filePacket.CopyTo(packetQueue[nextBufIndexToProduce]); nextBufIndexToProduce++; if (nextBufIndexToProduce == queueDepth) { nextBufIndexToProduce = 0; } queueFilledCount++; }
ReaderCompressorSharedState(int queueDepth, int packetSize) { this.queueDepth = queueDepth; this.packetSize = packetSize; packetQueue = new FilePacketArray[queueDepth]; for (var i = 0; i < queueDepth; i++) { packetQueue[i] = new FilePacketArray(0, packetSize); } eventsForProducer[(int)EventsForProducer.SpaceAppeared] = eventForNewSpaceInQueue; eventsForProducer[(int)EventsForProducer.Cancel] = eventForWorkCancellation; eventsForConsumer[(int)EventsForConsumer.PacketAppeared] = eventForFirstPacketInQueue; eventsForConsumer[(int)EventsForConsumer.ReadCompleted] = eventForInputCompletion; eventsForConsumer[(int)EventsForConsumer.Cancel] = eventForWorkCancellation; }
/// <summary> /// Thread's execution body /// </summary> void RunThread() { try { using (var fileStream = File.OpenRead(file)) { int bytesRead; var packet = new FilePacketArray(0, bufSize); var count = 0; while ((bytesRead = fileStream.Read(packet.Buffer, 0, bufSize)) > 0) { packet.FilledLength = bytesRead; outputState.Produce(packet, out var cancel); if (cancel) { return; } packet.IncIndex(); count++; } if (count == 0) // If file is empty { packet.FilledLength = 0; outputState.Produce(packet, out var cancel); } outputState.ReadCompleted(); } } catch (IOException) { SafeCancel(); Console.WriteLine("Could not read the file."); } catch (Exception ex) { SafeCancel(); Console.WriteLine("Error in file reading thread: " + ex.ToString()); } }
/// <summary> /// Saving "packet" of file /// </summary> /// <param name="filePacket">Piece of source file</param> /// <param name="cancel">Cancellation flag</param> public void Produce(FilePacketArray filePacket, out bool cancel) { Debug.Assert(filePacket != null, $"{nameof(filePacket)} is null"); Debug.Assert(filePacket.Index >= 0, $"{nameof(filePacket)}.{nameof(filePacket.Index)} must be not negative zero-based index"); var taken = true; mutex.WaitOne(); try { cancel = cancelled; if (cancelled) { return; } var eventType = EventsForProducer.SpaceExists; // If queue is full, start awaiting for free space while (queueFilledCount == queueDepth) { taken = false; mutex.ReleaseMutex(); eventType = (EventsForProducer)WaitHandle.WaitAny(eventsForProducer); mutex.WaitOne(); taken = true; if ((eventType == EventsForProducer.SpaceAppeared && queueFilledCount != queueDepth) || eventType == EventsForProducer.Cancel) { break; } } switch (eventType) { case EventsForProducer.SpaceExists: case EventsForProducer.SpaceAppeared: Enqueue(filePacket); if (queueFilledCount == 1) // If it is a first packet in queue, setting signal for consumers { eventForFirstPacketInQueue.Set(); } if (eventType == EventsForProducer.SpaceAppeared && queueFilledCount == queueDepth) { eventForNewSpaceInQueue.Reset(); // Resetting our signal about appearing of free space } break; case EventsForProducer.Cancel: cancel = true; break; default: Debug.Write($"Unsupported event type for producer: {Enum.GetName(typeof(EventsForProducer), eventType)}"); break; } } finally { if (taken) { mutex.ReleaseMutex(); } } }