使用Mutex类

                class Program
{
static void Main(string[] args)
{
const string MutexName ="CSharpThreadingCookbook";
using (var m = new Mutex(false, MutexName))
{
if (!m.WaitOne(TimeSpan.FromSeconds(5), false))
{
Console.WriteLine("Second instance is running!");
}
else {
Console.WriteLine("Runing!");
Console.ReadLine();
m.ReleaseMutex();
}
}
}
}

当主程序启动时,定义了一个指定名称的互斥量,设置initialowner标志为false。这意味着如果互斥量已经被创建,则允许程序获取该互斥量。如果没有获取到互斥量,程序则简单的显示running,的等待知道按下了任何键,然后释放该互斥量并退出。 如果再运行同样一个程序,则会在5秒内尝试获取互斥量。如果此时在第一个程序中按下了任何键,第二个程序则会开始执行。然而,如果保持等待5秒钟,第二个程序将无法获取到该互斥量。 该方式可用于在不同的程序中同步线程,可被推广到大量的使用场景中。

使用SemaphoreSilm类

            static SemaphoreSlim _semaphore = new SemaphoreSlim(4);

            static void AccessDatabase(string name, int seconds) {
Console.WriteLine("{0} waits to access a database",name);
_semaphore.Wait();
Console.WriteLine("{0} was granted an access to a database",name);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0} is completed",name);
_semaphore.Release(); }
             static void Main(string[] args)
{
for (int i = 1; i <= 6; i++) {
string threadName ="Thread" + i;
int secondsToWait = 2 + 2 * i;
var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
t.Start();
}
Console.ReadKey();
}
当主程序启动时,创建了SemaphoreSlim的一个实例,并在其构造函数中指定允许的并发线程数量。然后启动了6个不同名称和不同初始运行时间的线程。每个线程都尝试获取数据库的访问,但是我们借助于信号系统限制了访问数据库的并发数为4个线程。当有4个线程获取数据库的访问后,其他两个线程需要等待,直到之前线程中的某一个完成工作并调用_semaphore.Release方法来发出信号。

使用AutoResetEvent类

            private staticAutoResetEvent _workerEvent=new AutoResetEvent(false);
private staticAutoResetEvent _mainEvent =new AutoResetEvent(false);
static void Process(int seconds)
{
Console.WriteLine("Starting a long running work... ");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("Work is done!");
_workerEvent.Set();
Console.WriteLine("Waiting for a main thread to complete its work");
_mainEvent.WaitOne();
Console.WriteLine("starting second operation... ");
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("Work is done!");
_workerEvent.Set();
}
            static void Main(string[] args)
{
var t = new Thread(() => Process(10));
t.Start();
Console.WriteLine("Waiting for a main thread to complete its work");
_workerEvent.WaitOne();
Console.WriteLine("First operation is completed!");
Console.WriteLine("Performing an operation on a main thread");
Thread.Sleep(TimeSpan.FromSeconds(5));
_mainEvent.Set();
Console.WriteLine("Now running the second operation on a second thread");
_workerEvent.WaitOne();
Console.WriteLine("Second operation is completed!");
}
当主程序启动时,定义了两个autoresetEvent实例。其中一个是从子线程向主线程发信号,另一个实例是从主线程向子线程发信息号 。我们向AutoResetEvent构造方法传入false,定义了这两个实例初始状态为unsignaled。这意味着我们任何线程调用这两个对象中的任何一个 waitone方法将会被堵塞,直到我们调用了set方法。如果初试事件为true,那么autoresetEvent实例的状态为sigaled,如果线程调用waitone方法则会立即处理。 然后事件状态自动变为unsignaled,所以需要再对改实例调用一次set方法,以便让其他的线程对该实例调用waitone方法从而继续执行。 然后我们创建了第二个线程,其会执行第一个操作10秒钟,然后等待从第二个线程发出的信号。该信号意味着第一个操作已经完成。现在第二个线程在 等待主线程的信号,我们对主线程做了一些1附加工作,并通过调用_mainEvent.Set方法发送了一个信号。然后等待从第二个线程发出的另一个信号 AutoResetEvent类采用的是内核时间模式,所以等待时间不能太长。使用2.6节中的ManualResetEventslim类更好,因为他使用的是混合模式。

最新文章

  1. Linux 系统中堆栈的使用方法
  2. ecmall中static变量的使用-model模型代码设计
  3. MEF入门之不求甚解,但力求简单能讲明白(五)
  4. linux 无线网络配置工具wpa_supplicant与wireless-tools
  5. Code Review for SSIS package
  6. 为什么iphone手机比android手机流畅
  7. WP 前台或后台显示ShellToast
  8. [Usaco2008 Open]Roads Around The Farm分岔路口[水题]
  9. \r,\n,\r\n的区别和用法
  10. Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD
  11. 雅礼 noip2018 模拟赛 day3 T3
  12. Divide by Zero 2018 and Codeforces Round #474 (Div. 1 + Div. 2, combined)
  13. python 迭代器/生成器/迭代对象
  14. 一般来说,主方法main()结束的时候线程结束
  15. [OpenJudge90][序列DP+乱搞]滑雪
  16. Linux系统维护管理命令及vim编辑器
  17. ThinkPHP利用数据库字段做栏目的无限分类
  18. NYOJ-673悟空的难题~~水题~~
  19. MUI日期选择控件
  20. LigerUI 单独调用插件使用注意项

热门文章

  1. 记一次服务器Tomcat优化经历
  2. nvarchar 和varchar区别
  3. js返回格式化的日期(年-月-日)
  4. kafka 源代码分析之Message(v0.10)
  5. 【Android Developers Training】 57. 在UI线程之外处理图像
  6. AngularJS事件
  7. android app调试没问题,但打包签名的apk,运行时出现闪退怎么办?
  8. js的DOM操作
  9. 读书共享 Primer Plus C-part 7
  10. accp8.0转换教材第3章MySQL高级查询(一)理解与练习