基元线程同步构造之信号量(Semaphore)
信号量(semaphore)不过是由内核维护的 int32变量而已,(说通俗点就是好比一个线程容器里面允许执行的线程数,0计数就是允许执行的0个线程数,1就是允许执行的1个线程数,2就是允许执行的2个线程数,等等一次类推。。。。。。,0就是当前执行的线程数占满了容器没空余的了)。
当信号量为0时,在信号量上等待的线程会全部阻塞;
当信号量大于0时,就解除阻塞。
在一个信号量上等待的一个线程解除阻塞时,内核自动从信号量的计数中减1,线程运行完后调用Release,计数就加1。信号量还关联了一个最大的Int32值,当前计数绝不允许超过最大计数。下面展示了semaphore类的样子:
public sealed class Semaphore :WaitHandle{
//初始化信号量:初始请求数为initialCount,最大请求数为maximumCount
public Semaphore(Int32 initialCount,Int32 maximumCount);
public Int32 Release();//调用Release(1);返回上一个计数
public Int32 Release(Int32 releaseCount);//返回上一个计数
}
initialCount:就是初始化信号量时,解除阻塞的线程数。 maximumCount:就是信号量允许执行的最大线程数。
一个自动重置事件在行为上和最大计数为1的信号量非常相似。两者的区别在于,可以在一个自动重置事件上连续多次调用Set,同时仍然只有一个线程解除阻塞。相反,在一个信号量上连续多次调用Release,会使它的内部计数一直递增,这可能解除大量线程的阻塞。如果在一个信号量上多次调用Release,会导致它的计数超过最大计数,这是Release会抛出一个SemaphoreFullException.
请看MSDN中的一个例子:
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()
{
// Create a semaphore that can satisfy up to three
// concurrent requests. Use an initial count of zero,
// so that the entire semaphore count is initially
// owned by the main program thread.
//初始化时允许解除的阻塞线程数量为0,最大的执行线程数为3,所以在第执行完第44行代码之前,开启的子线程中的代码都不会执行,如果注释掉第45行代码,这5个子线程都不会执行,如果改成:new Semaphore(1,3)初始化时允许解除的阻塞线程数量为1,最大执行的线程数为3,所以在执行完31行代码后会有一个子线程在运行的,如果注释掉第45行代码,就会只有一个信号量慢慢的运行完这5个子线程
_pool = new Semaphore(, ); // Create and start five numbered threads.
//
for (int i = ; i <= ; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(Worker)); // Start the thread, passing the number.
//
t.Start(i);
} // Wait for half a second, to allow all the
// threads to start and to block on the semaphore.
//
Thread.Sleep(); // The main thread starts out holding the entire
// semaphore count. Calling Release(3) brings the
// semaphore count back to its maximum value, and
// allows the waiting threads to enter the semaphore,
// up to three at a time.
//
Console.WriteLine("Main thread calls Release(3).");
_pool.Release();//此句代码的通俗意思就是重新再增加3个可以执行的线程,如果初始化new semaphore(1,5)运行完这代代码就是1+3=4个线程数解除阻塞了,如果初始化为new semaphore(0,5)运行完这段代码就是0+3=3个线程数解除阻塞了。
//Console.WriteLine("_pool {0}", _pool.Release());
//Console.WriteLine("_pool {0}", _pool.Release());
//Console.WriteLine("_pool {0}", _pool.Release());
//Console.WriteLine("_pool {0}", _pool.Release());
//Console.WriteLine("_pool {0}", _pool.Release()); Console.WriteLine("Main thread exits."); // Thread.Sleep(5000);
// Console.WriteLine("_pool {0}", _pool.Release()); Console.ReadLine();
} private static void Worker(object num)
{
// Each worker thread begins by requesting the
// semaphore.
Console.WriteLine("Thread {0} begins " +
"and waits for the semaphore.", num);
_pool.WaitOne(); // A padding interval to make the output more orderly.
int padding = Interlocked.Add(ref _padding, ); Console.WriteLine("Thread {0} enters the semaphore.", num); // The thread's "work" consists of sleeping for
// about a second. Each thread "works" a little
// longer, just to make the output more orderly.
//模拟阻塞线程
Thread.Sleep(1000 + padding); Console.WriteLine("Thread {0} releases the semaphore.", num);
Console.WriteLine("Thread {0} previous semaphore count: {1}",
num, _pool.Release());
}
}
运行的其中之一的一个结果为:
Thread begins and waits for the semaphore.
Thread begins and waits for the semaphore.
Thread begins and waits for the semaphore.
Thread begins and waits for the semaphore.
Thread begins and waits for the semaphore.
Main thread calls Release().
Thread enters the semaphore.
Thread releases the semaphore.
Thread previous semaphore count:
Thread enters the semaphore.
Thread releases the semaphore.
Thread previous semaphore count:
Thread enters the semaphore.
Thread releases the semaphore.
Thread previous semaphore count:
Main thread exits.
Thread enters the semaphore.
Thread releases the semaphore.
Thread previous semaphore count: 1 //执行这段代码前。信号量(semaphore)中还有两个线程在执行(当前运行运行的线程和下面还没运行完的一个线程,所以剩余1个线程的信号量(semaphore)可以执行.
Thread enters the semaphore.
Thread releases the semaphore.
Thread previous semaphore count: 2 //执行这段代码前。信号量(semaphore)中有2个空闲的位置,可以执行线程了。
这只是自己的理解,不正确的望各位大侠们指教。。。。。。。。。。。。。。。
基元线程同步构造之信号量(Semaphore)的更多相关文章
- [.net]基元线程同步构造
/* 基元线程同步构造 用户模式构造: 易变构造(Volatile Construct) 互锁构造(Interlocked Construct):自旋锁(Spinlock) 乐观锁(Optimisti ...
- 基元线程同步构造之waithandle中 waitone使用
在使用基元线程同步构造中waithandle中waitone方法的讲解: 调用waithandle的waitone方法阻止当前线程(提前是其状态为Nonsignaled,即红灯),直到当前的 Wait ...
- 【C#进阶系列】28 基元线程同步构造
多个线程同时访问共享数据时,线程同步能防止数据损坏.之所以要强调同时,是因为线程同步问题实际上就是计时问题. 不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗 ...
- Clr Via C#读书笔记----基元线程同步构造
线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...
- 基元线程同步构造之 Mutes(互斥体)
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)). 互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section). 因 ...
- CLR via C# I/O基元线程同步构造
1. 分为用户模式构造和内核模式构造 2. 用户模式构造 a.易失构造 在一个简单数据类型的变量上执行原子性读或写操作 VolaileWrite 强制address中的值在调用时写入,除此之外,按照源 ...
- 基元线程同步构造 AutoResetEvent和ManualResetEvent 线程同步
在.Net多线程编程中,AutoResetEvent和ManualResetEvent这两个类经常用到, 他们的用法很类似,但也有区别.ManualResetEvent和AutoResetEvent都 ...
- 【C#进阶系列】29 混合线程同步构造
上一章讲了基元线程同步构造,而其它的线程同步构造都是基于这些基元线程同步构造的,并且一般都合并了用户模式和内核模式构造,我们称之为混合线程同步构造. 在没有线程竞争时,混合线程提供了基于用户模式构造所 ...
- 【C#】C#线程_基元线程的同步构造
目录结构: contents structure [+] 简介 为什么需要使用线程同步 线程同步的缺点 基元线程同步 什么是基元线程 基元用户模式构造和内核模式构造的比较 用户模式构造 易变构造(Vo ...
随机推荐
- 因环境变量设置问题引起的command not found
ls command not found vi command not found 只要的原因是因为环境变量的问题,编辑profile文件没有写正确,导致在命令行下 ls等命令不能够识别.解决办法:在 ...
- 最新hadoop虚拟机安装教程(附带图文)
前两天看到有人留言问在什么情况下需要部署hadoop,我给的回答也很简单,就是在需要处理海量数据的时候才需要考虑部署hadoop.关于这个问题在很早之前的一篇分享文档也有说到这个问题,数据量少的完全发 ...
- Mac 平台安装 Android Studio 集成 Android SDK
最近写个小工具,给周边一些朋友用用(类似任务执行),一开始 任务执行用Python写的,部署在云端,有一些局限(资金开销):现准备写一个任务端,需要用到的人直接装个客户端就行,于是准备写个客户端版本的 ...
- linux svn安装(转载)
第一章 安装 1. 采用源文件编译安装.源文件共两个,为:subversion-1.6.1.tar.gz (subversion 源文件)subversion-deps-1.6.1.tar.gz (s ...
- 异步FIFO格雷码与空满
在传递读写时钟域的指针使用格雷码来传递,如何把二进制转换为格雷码,格雷码是如何判断读空写满呢? 二进制码转换成二进制格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高 ...
- 【ActiveMQ入门-10】ActiveMQ学习-通配符+异步接收
通配符介绍: 一般情况下,我们使用层次结构的方式来组织队列,比如A.B.C.D,这样便于归类和管理. 我们也可以使用通配符来配置或是操作多个队列. 通配符有三个: . 用来分隔路径: * 用来匹 ...
- jsoncpp解析拼装数组
Cocos2d-x添加jsoncpp应该资料都有了,今天来讲讲数组的解析和拼装- int main() { 数组创建与分析: 例子一: string strValue = "{\" ...
- hdu 1966 Pie
Pie Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- 接口测试3-2csv格式
csv文件数据 IntellJ IDEA打开终端:view-tool windows-terminal,可以在终端中查看文件路径 阿里 马云 京东 刘强东 京东 马化腾 #java //读取csv文件 ...
- Opencv 入门学习之图片人脸识别
读入图片,算法检测,画出矩形框 import cv2 from PIL import Image,ImageDraw import os def detectFaces(image_name): im ...