C# 多线程编程知识
BlockingCollection—生成者消费者模式
public static void Execute() { //调用Invoke,使得生产者任务和消费者任务并行执行 //Producer方法和Customer方法在Invoke中的参数顺序任意,不论何种顺序都会获得正确的结果 Parallel.Invoke(()=>Customer(),()=>Producer()); Console.WriteLine(string.Join(",",customerColl)); } //生成者集合 private static BlockingCollection<int> producerColl = new BlockingCollection<int>(); //消费者集合 private static BlockingCollection<string> customerColl = new BlockingCollection<string>(); public static void Producer() { //循环将数据加入生成者集合 for (int i = 0; i < 100; i++) { producerColl.Add(i); } //设置信号,表明不在向生产者集合中加入新数据 //可以设置更加复杂的通知形式,比如数据量达到一定值且其中的数据满足某一条件时就设置完成添加 producerColl.CompleteAdding(); } public static void Customer() { //调用IsCompleted方法,判断生成者集合是否在添加数据,是否还有未"消费"的数据 //注意不要使用IsAddingCompleted,IsAddingCompleted只表明集合标记为已完成添加,而不能说明其为空 //而IsCompleted为ture时,那么IsAddingCompleted为ture且集合为空 while (!producerColl.IsCompleted) { //调用Take或TryTake "消费"数据,消费一个,移除一个 //TryAdd的好处是提供超时机制 customerColl.Add(string.Format("消费:{0}", producerColl.Take())); } }
public static void Test() { var concurentDictionary = new ConcurrentDictionary<int, int>(); var w = new ManualResetEvent(false); int timedCalled = 0; var threads = new List<Thread>(); Lazy<int> lazy = new Lazy<int>(() => { Interlocked.Increment(ref timedCalled); return 1; }); for (int i = 0; i < Environment.ProcessorCount; i++) { threads.Add(new Thread(() => { w.WaitOne(); concurentDictionary.GetOrAdd(1, i1 => { return lazy.Value; }); })); threads.Last().Start(); } w.Set();//release all threads to start at the same time Thread.Sleep(100); Console.WriteLine(timedCalled);// output is 1 }
//方法一 //Thread subThread = new Thread(new ParameterizedThreadStart((threadParaData) => //{ // DownloadMultiPart dmp = new DownloadMultiPart(transferTask); // dmp.GetObjectPartly(); // ThreadArray.RemoveFile(transferTask); //})); //subThread.SetApartmentState(ApartmentState.STA); //subThread.IsBackground = true; //subThread.Start("paraData"); //方法二 //Task.Factory.StartNew(() => //{ // transferTask.TransferStatus = Enum.GetName(typeof(TransferEnum), TransferEnum.Doing); // transferTask.TransferLog = "正在下载……"; // DownloadMultiPart dmp = new DownloadMultiPart(); // dmp.GetObjectPartly(transferTask.FileServerPath, transferTask.TransferLocalPath); // transferTask.TransferStatus = Enum.GetName(typeof(TransferEnum), TransferEnum.Succeed); // transferTask.TransferLog = "下载成功."; // ThreadArray.RemoveFile(transferTask); //} //, System.Threading.CancellationToken.None //, System.Threading.Tasks.TaskCreationOptions.LongRunning //, System.Threading.Tasks.TaskScheduler.Default); //方法三 //Task.Factory // .StartNew(() => { }, // CancellationToken.None, // TaskCreationOptions.LongRunning, // guarantees separate thread 保证独立的线程 // TaskScheduler.Default) // .Wait(); //方法四 Task<int> t2 = new Task<int>((object obj) => { DownloadMultiPart dmp = new DownloadMultiPart(transferTask); dmp.GetObjectPartly(); ThreadArray.RemoveFile(transferTask); return 0; } , null , TaskCreationOptions.LongRunning); t2.Start(); //t2.Wait(); //int xxx = t2.Result;
Task<Func<string, int>> t1 = new Task<Func<string, int>>((paraTransferTask) => { string xxxx = paraTransferTask as string; ExtractPage(xxxx); return new Func<string, int>((y) => { return 0; }); } , filePath , TaskCreationOptions.LongRunning); t1.Start();
BackgroundWorker
ReaderWriterLock 用于同步对资源的访问。 在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。 在资源不经常发生更改的情况下,ReaderWriterLock 所提供的吞吐量比简单的一次只允许一个线程的锁(如 Monitor)更高。[注:lock关键字使用Monitor实现]
.NET Framework 具有两个读取器/编写器锁: ReaderWriterLockSlim 和 ReaderWriterLock。 建议在所有新的开发工作中使用 ReaderWriterLockSlim。 ReaderWriterLockSlim 类似于 ReaderWriterLock,但简化了递归规则以及升级和降级锁定状态的规则。 ReaderWriterLockSlim 可避免多种潜在的死锁情况。 此外, ReaderWriterLockSlim 的性能明显优于 ReaderWriterLock。
注意:长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。 为了得到最好的性能,需要考虑重新构造应用程序以将写访问的持续时间减少到最小。

浙公网安备 33010602011771号