当前位置: 首页 > news >正文

多线程总结之旅(8):线程同步之信号量

  

  上一篇我们介绍了互斥体,这一篇介绍信号量。。。。。。。。。。。。

   一、什么是信号量

    信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。

 

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


 

  二、信号量的使用原理?  

 

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

 

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

 

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

 

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

 

 

  


  三、示例    

    1、线程间的sempahore同步

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

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

    

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SemaphoreClass
{
    class Program
    {
        static void Main(string[] args)
        {
            int sourceCount = 4;//打印机数量            
            int threadCount = 6;//需要打印的线程数目
            
            // maximumCount-initialCount  之间的差值为已经锁定的 semaphore的数量(即信号量使用计数器)  此实例中已经指定占用了0个信号量
            //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
            Semaphore sempaphore = new Semaphore(sourceCount, sourceCount, "sempaphore");

            Thread[] threads = new Thread[threadCount];
            for (int i = 0; i < threadCount; i++)
            {
                threads[i] = new Thread(ThreadMain);
                threads[i].Start(sempaphore);
            }
            for (int i = 0; i < threadCount; i++)
            {
                threads[i].Join();
            }
            Console.WriteLine("All threads finished!");
            Console.ReadKey();
        }

        /// <summary>
        /// 线程执行的方法
        /// </summary>
        /// <param name="o"></param>
        static void ThreadMain(object o)
        {
            Semaphore semaphore = o as Semaphore;
            Trace.Assert(semaphore != null, "o must be a semphore type");

            bool isCompleted = false;
            while (!isCompleted)
            {
                //锁定信号量,如果锁定计数已经达到最高计数限制,则等待600毫秒。如果在600毫秒后未能获得锁定,则返回false。
                if (semaphore.WaitOne(600, false))
                {
                    try
                    {
                        Console.WriteLine("Thread {0} locks the semaphore ", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(2000);
                    }
                    finally
                    {
                        //解除资源的锁定。参数为退出信号量的次数。占用一个信号量故退出一个。
                        semaphore.Release(1);
                        Console.WriteLine("Thread {0} release the semaphore", Thread.CurrentThread.ManagedThreadId);
                        isCompleted = true;
                    }
                }
                else
                {
                    Console.WriteLine("Timeot for thread {0}; wait again", Thread.CurrentThread.ManagedThreadId);
                }
            }
        }
    }
}

 

  2、进程间的sempahore同步

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

 

  注意:生成解决方案后运行三次生成EXE,就会看到结果。信号量的进程同步和信号量的应用程序的名称无关。只要使用了同样名称的信号量,他们之前就存在了一种协约。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SemaphoreProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            //定义可同步运行的可用实例数
            int CreateNew = 2;

            //定义可同步运行的最大实例数
            int MaxCreateNew = 5;

            // maximumCount-initialCount  之间的差值为已经锁定的 semaphore的数量  此实例中已经指定占用了3个信号量 计算方式为(MaxCreateNew-CreateNew)
            //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步
            System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(CreateNew, MaxCreateNew, "sempaphoreProcess");

            if (sempaphore.WaitOne(100, false))
            {
                Console.WriteLine("系统正在运行……");
                Console.ReadKey();
            }
            else
            {
                MessageBox.Show("当前已经有 " + CreateNew + " 个实例在运行,系统将退出!", "您好", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }
    }
}

  

 

 

 

下一篇介绍事件。。。。。。。。。。。。

转载于:https://www.cnblogs.com/qtiger/p/5826819.html

相关文章:

  • java类初始化顺序
  • bootstrap总结
  • java创建对象的四种方式
  • java基础之String
  • 为什么单例对象的并发调用需要同步?
  • Spring_事务(1)
  • java集合框架总结
  • LeetCode-Count Bits
  • Java中对HashMap的深度分析与比较
  • java 线程小结
  • JAVA中精确计算金额BigDecimal
  • java并发编程实践笔记
  • 第四章 進程調度
  • volatile原理与技巧
  • java I/O的基本使用
  • [Vue CLI 3] 配置解析之 css.extract
  • 【css3】浏览器内核及其兼容性
  • Angularjs之国际化
  • ES6简单总结(搭配简单的讲解和小案例)
  • JDK 6和JDK 7中的substring()方法
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Redis学习笔记 - pipline(流水线、管道)
  • 测试开发系类之接口自动化测试
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 关于springcloud Gateway中的限流
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (14)Hive调优——合并小文件
  • (31)对象的克隆
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二十三)Flask之高频面试点
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (一)SpringBoot3---尚硅谷总结
  • (原)Matlab的svmtrain和svmclassify
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .NET 设计模式初探
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
  • .NET中使用Protobuffer 实现序列化和反序列化
  • @ComponentScan比较
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [8-23]知识梳理:文件系统、Bash基础特性、目录管理、文件管理、文本查看编辑处理...
  • [android] 请求码和结果码的作用
  • [BZOJ4016][FJOI2014]最短路径树问题
  • [C/C++]关于C++11中的std::move和std::forward
  • [C++]C++基础知识概述
  • [CTO札记]盛大文学公司名称对联
  • [Electron]ipcMain.on和ipcMain.handle的区别
  • [ES-5.6.12] x-pack ssl
  • [Leetcode] 寻找数组的中心索引
  • [LeetCode]-225. 用队列实现栈
  • [MySQL复制异常]Cannot execute statement: impossible to write to binary log since statement is in row for