随笔 - 547  文章 - 213 评论 - 417 阅读 - 107万

1.多线程

从dotNet4.0开始,出现了Parallel.ForEach函数,可以很方便的实现多线程。

但是由于.net4.0和.net3.5是不同的运行时,有的程序必须使用dotNet3.5。这个时候要使用多线程就比较麻烦。

.net 3.5中除了可以自己new Thread以外,一个比较强大的功能就是ThreadPool类,可以通过ThreadPool.QueueUserWorkItem很方便的进行多线程,而且不用考虑线程数和系统性能,.net会帮你处理这些杂事。

但是有一个很麻烦的事情,就是在主线程中如何去监控所有子线程的运行状态。通常的一个需求是等所有子线程执行完毕后,主线程输出一个提示消息。

.net3.5提供了一些类,但都差强人意。比如ManualResetEvent,这个可以显示监控多线程,但是最大支持数是64, 也就是说,我要执行多线程,需要将需要执行的任务分成64份或者其他少于64的份数,然后在一对一的用ManualResetEvent进行监控。这样做的缺点有二:1. 需要自己手动分任务,分出来的任务未必均衡。2. 最大数是64,可能无法充分利用资源。3. 很难做到线程的重复利用。

所以这里就要用到一个不太常用的东东,信号数(Semaphore). 它的原理是这样的:构造Semaphore时,可以指定一个数,这个数量就是系统锁定的资源数量。由于Semaphore是跨线程的。所以我们可以在主线程中根据子线程的数目来指定信号数,然后调用n次Semaphore.WaitOne, 在每个子线程释放一个资源,所有子线程执行完后,信号数释放完毕,主线程中的n个WaitOne都得以返回,这个时候就可以输出执行成功的信息了。

代码示例如下:

using System;

using System.Threading;

 

public class Example

{

// A semaphore that simulates a limited resource pool.

//

private static Semaphore _pool;

 

// A padding interval to make the output more orderly.

private static int _padding;

 

public static void Main()

{

_pool = new Semaphore(0, 5);

 

// Create and start five numbered threads.

//

for (int i = 1; i <= 5; i++)

{

Thread t = new Thread(new ParameterizedThreadStart(Worker));

 

// Start the thread, passing the number.

//

t.Start(i);

}

 

for (int i = 0; i < 5; i++)

{

_pool.WaitOne();

}

 

Console.WriteLine("All threads finished.");

 

Console.ReadLine();

}

 

private static void Worker(object num)

{

Console.WriteLine("Thread {0} starts", num);

Thread.Sleep(2000);

Console.WriteLine("Thread {0} ends", num);

_pool.Release();

 

 

}

}

 

执行结果如下:

2.进度显示

如果一个线程执行时间很长,用户无法判断程序是否在执行。这种情况我们可以通过信号数来给用户提示。原理就是:Semaphore.WaitOne接收一个参数,传入这个参数后,每过一个时间间隔,Semaphore返回一次,如果是true,代表等待的资源已经被释放,如果是false,代表还在继续等待。这样我们就可以每隔一段时间给用户一个提示。

 

代码示例如下:

using System;

using System.Threading;

 

public class Example

{

// A semaphore that simulates a limited resource pool.

//

private static Semaphore _pool;

 

// A padding interval to make the output more orderly.

private static int _padding;

 

public static void Main()

{

_pool = new Semaphore(0, 5);

 

// Create and start five numbered threads.

//

for (int i = 1; i <= 5; i++)

{

Thread t = new Thread(new ParameterizedThreadStart(Worker));

 

// Start the thread, passing the number.

//

t.Start(i);

}

 

int totalThread = 5;

for (int i = 0; i < 5; i++)

{

bool flag = false;

do

{

flag = _pool.WaitOne(500);

Console.WriteLine("Remained threads: {0}", totalThread);

}

while (!flag);

totalThread--;

}

 

Console.WriteLine("All threads finished.");

 

Console.ReadLine();

}

 

private static void Worker(object num)

{

Console.WriteLine("Thread {0} starts", num);

Thread.Sleep(2000);

Console.WriteLine("Thread {0} ends", num);

_pool.Release();

 

 

}

}

 

运行结果如下:

3.广泛应用

信号数(Semaphore)不但可以跨线程,而且可以跨应用程序,在整个操作系统级别进行同步。以下是msdn的描述:

Semaphores are of two types: local semaphores and named system semaphores. If you create a Semaphore object using a constructor that accepts a name, it is associated with an operating-system semaphore of that name. Named system semaphores are visible throughout the operating system, and can be used to synchronize the activities of processes. You can create multiple Semaphore objects that represent the same named system semaphore, and you can use the OpenExisting method to open an existing named system semaphore.

A local semaphore exists only within your process. It can be used by any thread in your process that has a reference to the local Semaphore object. Each Semaphore object is a separate local semaphore.

posted on   今夜太冷  阅读(1216)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示