static void Main(string[] args) { var mre = new ManualResetEventSlim(); var memoryTask = Task.Run(() => { while (!mre.IsSet) { Console.SetCursorPosition(0, 0); Console.WriteLine($"Process ID: {Environment.ProcessId}"); Console.Write("Working, press any key to stop..."); Console.WriteLine(); GCUtils.PrintInfoAboutLastCycle(); Thread.Sleep(1000); } }); var task = Task.Run(() => { var timer = new System.Timers.Timer(500); timer.Start(); int x = 0; while (!mre.IsSet) { var eventDispatcher = new TimerEventDispatcher(timer); eventDispatcher.TimerElapsedNow += EventDispatcher_TimerElapsedNow; if (++x % 2000 == 0) { Thread.Sleep(50); } } }); Console.ReadKey(); mre.Set(); Task.WaitAll(task, memoryTask); Console.WriteLine("OK, bye!"); }
public static void Test() { var source = new PropertyChangedEventSource(); var listener = new PropertyChangedEventEventListener(); //Register listener to the source PropertyChangedEventManager.AddListener(source, listener, nameof(PropertyChangedEventSource.Name)); //change property change and the ReceiveWeakEvent of PropertyChangedEventEventListener method will be called source.Name = "first name"; //set listener to null so it will be ready for gc listener = null; //trigger gc and the listener will be collected. GCUtils.TriggerGC(); //change property value but the ReceiveWeakEvent of PropertyChangedEventEventListener method will NOT be called source.Name = "second name"; Console.Read(); }
public static void Test() { var eventSource = new CustomEventSource(); var listener = new CustomEventListener(); //add handler listener.HandleEvent to CustomEvent of CustomEventSource WeakEventManager <CustomEventSource, CustomEventArg> .AddHandler(eventSource, "CustomEvent", listener.HandleEvent); //trigger event and listener.HandleEvent will be executed eventSource.Raise("First message"); //set listener to null listener = null; //trigger gc and the listener object will be collected. GCUtils.TriggerGC(); //trigger event and listener.HandleEvent stil will NOT be executed eventSource.Raise("Second Message"); Console.Read(); }
public static void Test() { var eventSource = new CustomEventSource(); var listener = new CustomEventListener(); //register event listener eventSource.CustomEvent += listener.HandleEvent; //trigger event and listener.HandleEvent will be executed eventSource.Raise("First Message from CustomEventSource"); //set listener to null listener = null; //trigger gc but the listener object will NOT collected. GCUtils.TriggerGC(); //trigger event and listener.HandleEvent stil will be executed eventSource.Raise("Second Message from CustomEventSource"); Console.Read(); }
public static void Test() { var eventSource = new CustomEventSource(); var listener = new CustomWeakEventListener(); //add listener for eventSource via CustomizedWeakEventManager CustomizedWeakEventManager.AddListener(eventSource, listener); //trigger event and listener.ReceiveWeakEvent will be executed eventSource.Raise("First message"); //set listener to null listener = null; //trigger gc and the listener object will be collected. GCUtils.TriggerGC(); //trigger event and listener.HandleEvent stil will NOT be executed eventSource.Raise("Second Message"); Console.Read(); }
/// <summary> /// Читаем блоки файла для архивации /// </summary> /// <param name="filepath">Входной файл</param> /// <param name="bufferSize">Размер блока</param> private void ReadForCompress(string filepath, int bufferSize) { var fileLength = new FileInfo(filepath).Length; var availableBytes = fileLength; while (availableBytes > 0) { while (_maxChunks != 0 && InputChunkHolder.Count >= _maxChunks) { lock (InputChunkHolder.DequeueWaitObject) { Monitor.Wait(InputChunkHolder.DequeueWaitObject); } } while (GCUtils.FreeMemoryMb() < Constants.MinMemoryFreeMb) { //Console.WriteLine(GCUtils.FreeMemoryMb()+"Mb left!"); GCUtils.ForceGc(); } //сколько читать var readCount = availableBytes < bufferSize ? (int)availableBytes : bufferSize; using (var reader = new BinaryReader(File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.Read))) { reader.BaseStream.Seek(fileLength - availableBytes, SeekOrigin.Begin); var bytes = reader.ReadBytes(readCount); InputChunkHolder.Enqueu(new Chunk(ChunksReaded, bytes)); } //двигаем счётчики availableBytes -= readCount; ChunksReaded++; //Console.WriteLine($"Readed #{ChunksReaded-1}"); } FileReaded = true; //Console.WriteLine($"Total chunks {ChunksReaded-1}"); }
public void Start() { _isExecuting = true; while (true) { GCUtils.FreeMemoryOptimizer(Constants.MinimalAvailableMemoryInPercentages); if (!_isExecuting || (_queue.Count() == 0 && _threadPool.Count == 0)) // Stop execution or all tasks done. { break; } if (_threadPool.Count == _maxThreadsCount) // The whole pool is busy with threads. { continue; } var task = _queue.Dequeue(); if (task == null) // All tasks from the queue are pulled out. { continue; } task.TaskDone += (sender, args) => { lock (_lock) _threadPool.Remove(args.Thread); }; _totalTasks++; var thread = new Thread(() => task.Start()) { Name = "GZipTask" + _totalTasks, Priority = ThreadPriority.AboveNormal }; lock (_lock) _threadPool.Add(thread); thread.Start(); } _isExecuting = false; _totalTasks = 0; }
static void Main(string[] args) { var mre = new ManualResetEventSlim(); var memoryTask = Task.Run(() => { while (!mre.IsSet) { Console.SetCursorPosition(0, 0); Console.WriteLine($"Process ID: {Environment.ProcessId}"); Console.Write("Working, press any key to stop..."); Console.WriteLine(); GCUtils.PrintInfoAboutLastCycle(); Thread.Sleep(1000); } }); var task = Task.Run(() => { while (!mre.IsSet) { //note: PhysicalFileProvider under the hood uses unmanaged resources (see https://github.com/dotnet/runtime/blob/master/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Win32.cs#L32) try { var fp = new PhysicalFileProvider(Path.GetTempPath()); fp.Watch("*.*"); } catch (Exception) { } } }); Console.ReadKey(); mre.Set(); Task.WaitAll(task, memoryTask); Console.WriteLine("OK, bye!"); }
public static StackValue Coerce(StackValue sv, Type targetType, Core core) { //@TODO(Jun): FIX ME - abort coersion for default args if (sv.IsDefaultArgument) { return(sv); } if (!( sv.metaData.type == targetType.UID || (core.ClassTable.ClassNodes[sv.metaData.type].ConvertibleTo(targetType.UID)) || sv.IsArray)) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kConversionNotPossible, ProtoCore.StringConstants.kConvertNonConvertibleTypes); return(StackValue.Null); } //if it's an array if (sv.IsArray && !targetType.IsIndexable) { //This is an array rank reduction //this may only be performed in recursion and is illegal here string errorMessage = String.Format(ProtoCore.StringConstants.kConvertArrayToNonArray, core.TypeSystem.GetType(targetType.UID)); core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kConversionNotPossible, errorMessage); return(StackValue.Null); } if (sv.IsArray && targetType.IsIndexable) { Validity.Assert(sv.IsArray); //We're being asked to convert an array into an array //walk over the structure converting each othe elements var hpe = core.Heap.GetHeapElement(sv); #if GC_REFERENCE_COUNTING var isTemporary = hpe.Active && hpe.Refcount == 0; #else var isTemporary = false; #endif if (targetType.UID == (int)PrimitiveType.kTypeVar && targetType.rank == DSASM.Constants.kArbitraryRank && isTemporary) { return(sv); } //Validity.Assert(targetType.rank != -1, "Arbitrary rank array conversion not yet implemented {2EAF557F-62DE-48F0-9BFA-F750BBCDF2CB}"); //Decrease level of reductions by one Type newTargetType = new Type(); newTargetType.UID = targetType.UID; if (targetType.rank != Constants.kArbitraryRank) { newTargetType.rank = targetType.rank - 1; } else { if (ArrayUtils.GetMaxRankForArray(sv, core) == 1) { //Last unpacking newTargetType.rank = 0; } else { newTargetType.rank = Constants.kArbitraryRank; } } return(ArrayUtils.CopyArray(sv, newTargetType, core)); } if (!sv.IsArray && !sv.IsNull && targetType.IsIndexable && targetType.rank != DSASM.Constants.kArbitraryRank) { //We're being asked to promote the value into an array if (targetType.rank == 1) { Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.Name = targetType.Name; newTargetType.rank = 0; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, core); GCUtils.GCRetain(coercedValue, core); StackValue newSv = core.Heap.AllocateArray(new StackValue[] { coercedValue }, null); return(newSv); } else { Validity.Assert(targetType.rank > 1, "Target rank should be greater than one for this clause"); Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.Name = targetType.Name; newTargetType.rank = targetType.rank - 1; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, core); GCUtils.GCRetain(coercedValue, core); StackValue newSv = core.Heap.AllocateArray(new StackValue[] { coercedValue }, null); return(newSv); } } if (sv.IsPointer) { StackValue ret = ClassCoerece(sv, targetType, core); return(ret); } //If it's anything other than array, just create a new copy switch (targetType.UID) { case (int)PrimitiveType.kInvalidType: Validity.Assert(false, "Can't convert invalid type"); break; case (int)PrimitiveType.kTypeBool: return(sv.ToBoolean(core)); case (int)PrimitiveType.kTypeChar: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeChar }; return(newSV); } case (int)PrimitiveType.kTypeDouble: return(sv.ToDouble()); case (int)PrimitiveType.kTypeFunctionPointer: if (sv.metaData.type != (int)PrimitiveType.kTypeFunctionPointer) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.StringConstants.kFailToConverToFunction); return(StackValue.Null); } return(sv); case (int)PrimitiveType.kTypeHostEntityID: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeHostEntityID }; return(newSV); } case (int)PrimitiveType.kTypeInt: { if (sv.metaData.type == (int)PrimitiveType.kTypeDouble) { //TODO(lukechurch): Once the API is improved (MAGN-5174) //Replace this with a log entry notification //core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeConvertionCauseInfoLoss, ProtoCore.StringConstants.kConvertDoubleToInt); } return(sv.ToInteger()); } case (int)PrimitiveType.kTypeNull: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.StringConstants.kFailToConverToNull); return(StackValue.Null); } return(sv); } case (int)PrimitiveType.kTypePointer: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.StringConstants.kFailToConverToPointer); return(StackValue.Null); } return(sv); } case (int)PrimitiveType.kTypeString: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeString }; if (sv.metaData.type == (int)PrimitiveType.kTypeChar) { char ch = EncodingUtils.ConvertInt64ToCharacter(newSV.opdata); newSV = StackValue.BuildString(ch.ToString(), core.Heap); } return(newSV); } case (int)PrimitiveType.kTypeVar: { return(sv); } case (int)PrimitiveType.kTypeArray: { return(ArrayUtils.CopyArray(sv, targetType, core)); } default: if (sv.IsNull) { return(StackValue.Null); } else { throw new NotImplementedException("Requested coercion not implemented"); } } throw new NotImplementedException("Requested coercion not implemented"); }
public static StackValue Coerce(StackValue sv, Type targetType, Core core) { //@TODO(Jun): FIX ME - abort coersion for default args if (sv.optype == AddressType.DefaultArg) { return(sv); } if (!( (int)sv.metaData.type == targetType.UID || (core.DSExecutable.classTable.ClassNodes[(int)sv.metaData.type].ConvertibleTo(targetType.UID)) || sv.optype == AddressType.ArrayPointer)) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kConversionNotPossible, ProtoCore.RuntimeData.WarningMessage.kConvertNonConvertibleTypes); return(StackUtils.BuildNull()); } //if it's an array if (sv.optype == AddressType.ArrayPointer && !targetType.IsIndexable && targetType.rank != DSASM.Constants.kUndefinedRank)// && targetType.UID != (int)PrimitiveType.kTypeVar) { //This is an array rank reduction //this may only be performed in recursion and is illegal here string errorMessage = String.Format(ProtoCore.RuntimeData.WarningMessage.kConvertArrayToNonArray, core.TypeSystem.GetType(targetType.UID)); core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kConversionNotPossible, errorMessage); return(StackUtils.BuildNull()); } if (sv.optype == AddressType.ArrayPointer && targetType.IsIndexable) { Validity.Assert(ArrayUtils.IsArray(sv)); //We're being asked to convert an array into an array //walk over the structure converting each othe elements if (targetType.UID == (int)PrimitiveType.kTypeVar && targetType.rank == DSASM.Constants.kArbitraryRank && core.Heap.IsTemporaryPointer(sv)) { return(sv); } HeapElement he = core.Heap.Heaplist[(int)sv.opdata]; StackValue[] newSubSVs = new StackValue[he.VisibleSize]; //Validity.Assert(targetType.rank != -1, "Arbitrary rank array conversion not yet implemented {2EAF557F-62DE-48F0-9BFA-F750BBCDF2CB}"); //Decrease level of reductions by one Type newTargetType = new Type(); newTargetType.UID = targetType.UID; if (targetType.rank != ProtoCore.DSASM.Constants.kArbitraryRank) { newTargetType.rank = targetType.rank - 1; newTargetType.IsIndexable = newTargetType.rank > 0; } else { if (ArrayUtils.GetMaxRankForArray(sv, core) == 1) { //Last unpacking newTargetType.rank = 0; newTargetType.IsIndexable = false; } else { newTargetType.rank = ProtoCore.DSASM.Constants.kArbitraryRank; newTargetType.IsIndexable = true; } } for (int i = 0; i < he.VisibleSize; i++) { StackValue coercedValue = Coerce(he.Stack[i], newTargetType, core); GCUtils.GCRetain(coercedValue, core); newSubSVs[i] = coercedValue; } StackValue newSV = HeapUtils.StoreArray(newSubSVs, core); return(newSV); } if (sv.optype != AddressType.ArrayPointer && sv.optype != AddressType.Null && targetType.IsIndexable && targetType.rank != DSASM.Constants.kArbitraryRank) { //We're being asked to promote the value into an array if (targetType.rank == 1) { Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.IsIndexable = false; newTargetType.Name = targetType.Name; newTargetType.rank = 0; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, core); GCUtils.GCRetain(coercedValue, core); StackValue newSv = HeapUtils.StoreArray(new StackValue[] { coercedValue }, core); return(newSv); } else { Validity.Assert(targetType.rank > 1, "Target rank should be greater than one for this clause"); Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.IsIndexable = true; newTargetType.Name = targetType.Name; newTargetType.rank = targetType.rank - 1; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, core); GCUtils.GCRetain(coercedValue, core); StackValue newSv = HeapUtils.StoreArray(new StackValue[] { coercedValue }, core); return(newSv); } } if (sv.optype == AddressType.Pointer) { StackValue ret = ClassCoerece(sv, targetType, core); return(ret); } //If it's anything other than array, just create a new copy switch (targetType.UID) { case (int)PrimitiveType.kInvalidType: Validity.Assert(false, "Can't convert invalid type"); break; case (int)PrimitiveType.kTypeBool: return(sv.AsBoolean(core)); case (int)PrimitiveType.kTypeChar: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeChar }; return(newSV); } case (int)PrimitiveType.kTypeDouble: return(sv.AsDouble()); case (int)PrimitiveType.kTypeFunctionPointer: if (sv.metaData.type != (int)PrimitiveType.kTypeFunctionPointer) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.RuntimeData.WarningMessage.kFailToConverToFunction); return(StackUtils.BuildNull()); } return(sv.ShallowClone()); case (int)PrimitiveType.kTypeHostEntityID: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeHostEntityID }; return(newSV); } case (int)PrimitiveType.kTypeInt: { if (sv.metaData.type == (int)PrimitiveType.kTypeDouble) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeConvertionCauseInfoLoss, ProtoCore.RuntimeData.WarningMessage.kConvertDoubleToInt); } return(sv.AsInt()); } case (int)PrimitiveType.kTypeNull: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.RuntimeData.WarningMessage.kFailToConverToNull); return(StackUtils.BuildNull()); } return(sv.ShallowClone()); } case (int)PrimitiveType.kTypePointer: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeMismatch, ProtoCore.RuntimeData.WarningMessage.kFailToConverToPointer); return(StackUtils.BuildNull()); } StackValue ret = sv.ShallowClone(); return(ret); } case (int)PrimitiveType.kTypeString: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeString }; if (sv.metaData.type == (int)PrimitiveType.kTypeChar) { char ch = ProtoCore.Utils.EncodingUtils.ConvertInt64ToCharacter(newSV.opdata); newSV = StackUtils.BuildString(ch.ToString(), core.Heap); } return(newSV); } case (int)PrimitiveType.kTypeVar: { return(sv); } case (int)PrimitiveType.kTypeArray: { HeapElement he = core.Heap.Heaplist[(int)sv.opdata]; StackValue[] newSubSVs = new StackValue[he.VisibleSize]; for (int i = 0; i < he.VisibleSize; i++) { StackValue coercedValue = Coerce(he.Stack[i], targetType, core); GCUtils.GCRetain(coercedValue, core); newSubSVs[i] = coercedValue; } StackValue newSV = HeapUtils.StoreArray(newSubSVs, core); return(newSV); } default: if (sv.optype == AddressType.Null) { return(StackUtils.BuildNull()); } else { throw new NotImplementedException("Requested coercion not implemented"); } } throw new NotImplementedException("Requested coercion not implemented"); }
/// <summary> /// Resizes/scales the image data to the specified size and quality /// Refer: http://www.mindscapehq.com/blog/index.php/2012/02/28/windows-phone-7-working-with-camera-tasks/ /// </summary> /// <param name="stream">Image stream</param> /// <param name="width">Target width of the image</param> /// <param name="height">Target height of the image</param> /// <param name="quality">Target quality of the image</param> /// <returns>Formatted image</returns> private byte[] FormatImage(Stream stream, int width, int height, int quality) { WriteableBitmap target = null; BitmapImage image = null; try { JpegInfo info = ExifReader.ReadJpeg(stream, string.Empty); byte[] data = null; int angle = 0; switch (info.Orientation) { case ExifOrientation.TopLeft: case ExifOrientation.Undefined: angle = 0; break; case ExifOrientation.TopRight: angle = 90; break; case ExifOrientation.BottomRight: angle = 180; break; case ExifOrientation.BottomLeft: angle = 270; break; } if (angle > 0d) { target = RotateStream(stream, angle); } if (target == null) { stream.Seek(0, SeekOrigin.Begin); image = new BitmapImage(); image.SetSource(stream); target = new WriteableBitmap(image); } MemoryStream outStream = new MemoryStream(); target.SaveJpeg(outStream, width, height, (int)((PhoneApplicationPage)Mowbly.ActivePhoneApplicationPage).Orientation, quality); outStream.Seek(0, SeekOrigin.Begin); data = ((MemoryStream)outStream).ToArray(); outStream.Close(); outStream.Dispose(); outStream = null; Logger.Debug("Camera: Formatted image [JPG " + width + "x" + height + ";quality" + quality + "]"); return(data); } catch (Exception e) { throw e; } finally { if (image != null) { image.UriSource = null; image = null; } target = null; //outStream ,image,target are eligible for cleanup GCUtils.DoGC(); } }
/// <summary> /// Читаем блоки архива /// </summary> /// <param name="filepath">Входной файл</param> private void ReadForDecompress(string filepath) { using (var reader = new BinaryReader(File.Open(filepath, FileMode.Open, FileAccess.Read))) { var gzipHeader = Constants.GZipHeader; var fileLength = new FileInfo(filepath).Length; var availableBytes = fileLength; while (availableBytes > 0) { while (GCUtils.FreeMemoryMb() < Constants.MinMemoryFreeMb) { //Console.WriteLine(GCUtils.FreeMemoryMb() + "Mb left!"); GCUtils.ForceGc(); } var gzipBlock = new List <byte>(); //Console.WriteLine($"Reading #{ChunksReaded}"); // GZip Заголовок if (ChunksReaded == 0) // Получаем первый заголовок в файле. В остальных блоках - такой же { gzipHeader = reader.ReadBytes(gzipHeader.Length); availableBytes -= gzipHeader.Length; } gzipBlock.AddRange(gzipHeader); //добавляем хидер в блок // Данные блока архива var gzipHeaderMatchsCount = 0; while (availableBytes > 0) { while (_maxChunks != 0 && InputChunkHolder.Count >= _maxChunks) { lock (InputChunkHolder.DequeueWaitObject) { //Console.WriteLine("Waiting for Dq"); Monitor.Wait(InputChunkHolder.DequeueWaitObject); } } var curByte = reader.ReadByte(); gzipBlock.Add(curByte); availableBytes--; // Проверяем заголовок следующего блока if (curByte == gzipHeader[gzipHeaderMatchsCount]) { gzipHeaderMatchsCount++; if (gzipHeaderMatchsCount != gzipHeader.Length) { continue; } gzipBlock.RemoveRange(gzipBlock.Count - gzipHeader.Length, gzipHeader.Length); // Убираем заголовок следующего блока из текущего break; } gzipHeaderMatchsCount = 0; } //отправляем блок на обработку InputChunkHolder.Enqueu(new Chunk(ChunksReaded, gzipBlock.ToArray())); //номер блока ++ ChunksReaded++; //Console.WriteLine($"Readed #{ChunksReaded - 1}"); } } FileReaded = true; //Console.WriteLine($"Total chunks {ChunksReaded - 1}"); }
/// <summary> /// Начинает процесс обработки файла /// </summary> public void Run() { var sw = new Stopwatch(); sw.Start(); //Создаем поток чтения var r = new Reader(0); _readerThread = new Thread(() => r.Read(_parameters.Operation, _parameters.InputFile, Constants.ChunkSize)) { Name = "ReaderThread", Priority = ThreadPriority.AboveNormal }; //Создаем поток записи var w = new Writer(); _writerThread = new Thread(() => w.Write(_parameters.OutputFile)) { Name = "WriterThread", Priority = ThreadPriority.AboveNormal }; _memoryCheckThread = new Thread(() => GCUtils.RuntimeCheck(Constants.MinMemoryFreeMb)); _memoryCheckThread.Start(); //Запускаем чтение и запись _readerThread.Start(); _writerThread.Start(); //Console.WriteLine("Reader and Writer Started"); var totalTasks = 0; //Пока все не считано и не записано while (!Writer.FileWrited || !Reader.FileReaded) { //проверяем на прерывание if (_isTerminated) { lock (_lock) { for (var i = _pool.Count - 1; i >= 0; i--) { if (!_pool[i].IsAlive) { _pool[i].Abort(); } _pool.RemoveAt(i); } } break; } //Если весь пул занят lock (_lock) { if (_pool.Count == _processorCount) { //Проверяем, все ли потоки работают if (_pool.All(th => th.IsAlive)) { continue; } //Если не все, то убираем отработавшие for (var i = _pool.Count - 1; i >= 0; i--) { if (!_pool[i].IsAlive) { _pool.RemoveAt(i); } } } } //Когда есть свободные места, создаем новый поток IWorker worker; if (_parameters.Operation == OperationCode.Compress) { worker = new CompressWorker(); } else { worker = new DecompressWorker(); } totalTasks++; var thr = new Thread(() => worker.DoWork()) { Name = "Worker" + totalTasks, Priority = ThreadPriority.AboveNormal }; lock (_lock) { _pool.Add(thr); } thr.Start(); } sw.Stop(); MessageSystem.AddMessage(!_isTerminated ? $"Операция выполнена за {sw.Elapsed.TotalSeconds:F2} секунд" : $"Операция прервана после {sw.Elapsed.TotalSeconds:F2} секунд"); }