zoukankan      html  css  js  c++  java
  • 线程间同步之 semaphore(信号量)

    semaphore 可用于进程间同步也可用于同一个进程间的线程同步。

    semaphore 非常类似于mutex ,

    共同点:semaphore和mutex都是内核对象,都可用于进程间的同步,并且都特别占用系统资源(线程的同步包括用户模式下的同步和内核模式下的同步,如果用内核对象来同步被保护的资源,系统需要从用户模式切换到内核模式,这个时间大概是1000个cpu周期)。

    区别为:mutex只能由一个线程(进行)访问被保护的资源。semaphore 是一种带计数的mutex的锁定,可定义同时访问被保护的资源的线程数。

    信号量有一个使用计数器,这个使用计数器,是信号量的最大资源计数和当前资源计数的差值。

    信号量的规则如下:

    a、如果当前资源计数大于0,那么信号量处于触发状态。

    b、如果当前资源计数等于0,那么信号量处于未触发状态。

    c、系统绝对不会让当前资源计数变为负数。

    d、当前资源计数绝对不会大于最大最大资源计数

    如:6个进程需要同时使用打印机,而电脑上只有四台打印机,则打印机是被保护的资源,信号量为4。则需要用semaphore来同步。

    1、线程间的sempahore同步

    使用下面的例子来讲解(见注释部分):

     1        static void Main(string[] args)
    2 {
    3 int threadCount = 6;
    4 int sempaphoreCount = 4;
    5 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了0个信号量
    6 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
    7 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(sempaphoreCount, sempaphoreCount, "sempaphore");
    8
    9 Thread[] threads = new Thread[threadCount];
    10 for (int i = 0; i < threadCount; i++)
    11 {
    12 threads[i] = new Thread(ThreadMain);
    13 threads[i].Start(sempaphore);
    14 }
    15 for (int i = 0; i < threadCount; i++)
    16 {
    17 threads[i].Join();
    18 }
    19 Console.WriteLine("All threads finished!");
    20 Console.ReadKey();
    21 }
    22
    23 /// <summary>
    24 /// 线程执行的方法
    25 /// </summary>
    26 /// <param name="o"></param>
    27 static void ThreadMain(object o)
    28 {
    29 Semaphore semaphore = o as Semaphore;
    30 Trace.Assert(semaphore != null, "o must be a semphore type");
    31
    32 bool isCompleted = false;
    33 while (!isCompleted)
    34 {
    35 //锁定信号量,如果锁定计数已经达到最高计数限制,则等待600毫秒。如果在600毫秒后未能获得锁定,则返回false。
    36 if (semaphore.WaitOne(600, false))
    37 {
    38 try
    39 {
    40 Console.WriteLine("Thread {0} locks the semaphore ", Thread.CurrentThread.ManagedThreadId);
    41 Thread.Sleep(2000);
    42 }
    43 finally
    44 {
    45 //解除资源的锁定。参数为退出信号量的次数。占用一个信号量故退出一个。
    46 semaphore.Release(1);
    47 Console.WriteLine("Thread {0} release the semaphore", Thread.CurrentThread.ManagedThreadId);
    48 isCompleted = true;
    49 }
    50 }
    51 else
    52 {
    53 Console.WriteLine("Timeot for thread {0}; wait again", Thread.CurrentThread.ManagedThreadId);
    54 }
    55 }
    56 }

    注意:如果出现 WaitOne 就一个要有对应的Release 即获取信号量后,一定要释放。

    运行结果如下:

    可以看到,四个线程(11、12、13、14)获得了锁定。线程15,16需要等待。该等待会重复进行,直到获得锁定的线程之一解除了信号量的锁定。

    2、进程间的sempahore同步

    下面的例子将使用信号量来同步进程,一个应用程序可以有二个实例运行(如果只允许有一个实例来运行,最优之选是mutex,其次才是信号量)。虽然这个例子不太实用,但完全可以说明semaphore的特性。

    大家先看代码:

     1         static void Main(string[] args)
    2 {
    3 //定义可同步运行的可用实例数
    4 int CreateNew = 2;
    5
    6 //定义可同步运行的最大实例数
    7 int MaxCreateNew = 5;
    8
    9 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了3个信号量 计算方式为(MaxCreateNew-CreateNew)
    10 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
    11 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(CreateNew, MaxCreateNew, "sempaphoreProcess");
    12
    13 if (sempaphore.WaitOne(100, false))
    14 {
    15 Console.WriteLine("系统正在运行……");
    16 Console.ReadKey();
    17 }
    18 else
    19 {
    20 MessageBox.Show("当前已经有 " + CreateNew + " 个实例在运行,系统将退出!", "您好", MessageBoxButtons.OK, MessageBoxIcon.Information);
    21 }
    22
    23 }

    生成解决方案后运行三次程序:

    第一次运行和第二次运行结果如下:

    第三次运行结果如下:

     现在已经完成只允许有两个应用程序实例在同时运行。

    注意:信号量的进程同步和信号量的应用程序的名称无关。只要使用了同样名称的信号量,他们之前就存在了一种协约。

    参考资料:c#高级编程


  • 相关阅读:
    cocos2dLua3.17.2当在出厂就为 Android11 Version30的手机上黑屏,无法运行的问题 qd
    cocos2dLua3.17.2 + AS3.5.2 创建工程成功 qd
    getdata软件的使用
    下载及安装Python详细步骤
    【硬件知识】电路图标识符号
    Java中高级开发工程师最新面试题整理
    jquery获得值和控制值
    js 根据日期做星座联动,简洁
    Android remove default apk
    registry collection: right click menu(右键菜单清理)/navigator pane(我的电脑左边栏清理)
  • 原文地址:https://www.cnblogs.com/yuqilin/p/2214429.html
Copyright © 2011-2022 走看看