线程同步(三)—— 信号量

线程信号量和进程信号量类似,Unix提供了两套与信号量有关的API。POSIX和System V。两套API都可以在线程和进程中使用。

进程中使用信号量是为了保证临界资源的控制,线程中已经有了互斥锁,而且还有条件变量对线程进行控制,信号量是不是就有点多余了呢?

其实在进程中也是可以使用互斥锁和控制变量,信号量和线程锁看似类似,但实际上还是有本质区别。

线程锁:只能对临界资源进行01操作,CPU在某个时刻只允许一个线程占用。谁加锁谁解锁。

信号量:PV操作,对结构体内计数器进行增减,允许多个线程进入临界资源,也没有限制必须同一个线程对信号量进行占用和释放。

例如AB两个线程都在访问临界资源,C线程处于阻塞,只要AB任意释放,C即可获得信号量。

下面是与之前进程通信的SemOp类用于线程的代码。

  1 #include <pthread.h>
  2 #include <unistd.h>
  3 #include <sys/sem.h>
  4 #include <iostream>
  5
  6 using namespace std;
  7
  8 class ThreadInterface
  9 {
 10 public:
 11     void CreateThread(void* (*func)(void *),void *sem);
 12     void WaitThread();
 13 private:
 14     pthread_t m_pTread;
 15 };
 16
 17 void ThreadInterface::CreateThread(void* (*func)(void *),void *sem)
 18 {
 19     pthread_create(&m_pTread, NULL, func, sem);
 20 }
 21
 22 void ThreadInterface::WaitThread()
 23 {
 24     pthread_join(m_pTread, NULL);
 25 }
 26
 27 class SemOp
 28 {
 29 public:
 30     SemOp():m_iSemID(0){};
 31     void InitSem();
 32     void GetSem();
 33     void ReleaseSem();
 34     void DelSem();
 35 private:
 36     int m_iSemID;
 37 };
 38
 39 void SemOp::InitSem()
 40 {
 41     if ((m_iSemID = semget(IPC_PRIVATE, 1, 0600|IPC_CREAT)) <= 0)
 42         cout<<"get semID failure!"<<endl;
 43     semctl(m_iSemID, 0, SETVAL, 1);
 44 }
 45
 46 void SemOp::GetSem()
 47 {
 48     struct sembuf sem_get;
 49     sem_get.sem_num = 0;
 50     sem_get.sem_op = -1;
 51     sem_get.sem_flg = SEM_UNDO;
 52     semop(m_iSemID,&sem_get,1);
 53 }
 54
 55 void SemOp::ReleaseSem()
 56 {
 57     struct sembuf sem_release;
 58     sem_release.sem_num = 0;
 59     sem_release.sem_op = 1;
 60     sem_release.sem_flg = SEM_UNDO;
 61     semop(m_iSemID,&sem_release,1);
 62 }
 63
 64 void SemOp::DelSem()
 65 {
 66     semctl(m_iSemID, 0, IPC_RMID);
 67 }
 68
 69 class Service
 70 {
 71 public:
 72     static void* run(void *pSem)
 73     {
 74         SemOp *sem = reinterpret_cast<SemOp*>(pSem);//指针强转
 75         sem->GetSem();
 76         for (int i = 0; i < 5; ++i)
 77         {
 78             cout<<"This is thread 2!"<<endl;
 79             sleep(1);
 80         }
 81         sem->ReleaseSem();
 82     }
 83 };
 84
 85 int main()
 86 {
 87     Service Srv;
 88     ThreadInterface Thread;
 89     SemOp sem;
 90
 91     sem.InitSem();
 92     Thread.CreateThread(&Srv.run, &sem);    //向线程传入信号量
 93
 94     sem.GetSem();
 95     for (int i = 0; i < 5; ++i)
 96     {
 97         cout<<"This is thread 1!"<<endl;
 98         sleep(1);
 99     }
100     sem.ReleaseSem();
101     Thread.WaitThread();
102     sem.DelSem();
103     return 0;
104 }

测试结果:

结果和互斥锁效果一致,也可以配合条件变量使用!

时间: 2024-10-10 02:39:58

线程同步(三)—— 信号量的相关文章

线程同步之信号量

线程同步之信号量 Semaphore 信号量. 它维护一个计数,当值大于0时,信号量对象处于已传信状态.通常用数值表示可用资源的个数. WaitForSingleObject()令信号量减一:ReleaseSemaphore()令信号量加一. 线程同步之信号量,布布扣,bubuko.com

Python 线程同步锁, 信号量

同步锁 import time, threading def addNum(): global num num -= 1 num = 100 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print('final num:', num) 运行结果: final num:

c++线程同步之信号量

// MutexExDlg.h : 头文件 // #pragma once // CMutexExDlg 对话框 class CMutexExDlg : public CDialogEx { // 构造 public: CMutexExDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_MUTEXEX_DIALOG }; protected: virtual void DoDataExchange(CDataExchang

VC++线程同步(三) 临界区使用例子

临界区(Crtical Section)同步对象 用户模式下的同步对象 Win32中,最容易使用的一个同步机制就是(关键段)Critical Section, 某些共享资源具有互斥性,也就是它要求被互斥地使用,他也是用于资源的互斥, 在大部分情况下,使用临界区替换Mutex(Mutex是内核模式下的同步对象). 局限性:他只能用于同步单个进程中的线程. 在任何同步机制当中,无论是哪个操作系统下,都不要 长时间的锁住资源,如果一直锁定资源,就会一致阻止其他线程的执行, 使整个程序,处于完全停止的状

VC++线程同步(五) 信号量使用例子

信号量(Semaphore) 信号量是内核对象,使用几个形象的例子,进行描述. 1 假设有5个位置,而外面有很多人要进来,那么当5个位置被人占用了 后,其他人就必须排队等待,每个人使用时间不同,5个占用的位置,其中有两个完成了,那么,排队的人中,最前面的两个人进行可以使用,但是最多就是5个人同时能够使用,这就是信号量. 2 例如我们在服务器中创建了一个线程池,它由5个线程组成,也就意味着,最多同时处理5个请求,一旦超过5个,那么请求就放入缓冲中,当一个或多个请求(最多5个)完成后,那么从缓冲中拿

4线程同步:信号量

1 信号量 信号量可以有n把锁. 依赖的头文件 #include <semaphore.h> 函数声明 sem_t 表示信号量 int sem_init(sem_t *sem, int pshared,unsigned int value); 名称: sem_init 功能: initialize an unnamed semaphore,初始化信号量sem_t,初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享. 头文件: #include <semaphore.h>

一起talk C栗子吧(第一百一十六回:C语言实例--线程同步之互斥量二)

各位看官们,大家好,上一回中咱们说的是线程同步之信号量的例子,这一回咱们继续说该例子.闲话休提,言归正转.让我们一起talk C栗子吧! 我们在上一回中详细介绍了互斥量相关函数的用法,这一回中,我们介绍如何使用这些函数来操作互斥量. 下面是详细的操作步骤: 1.定义一个互斥量A,用来同步线程: 2.在创建线程的进程中使用pthread_mutex_init函数初始化互斥量,互斥量的属性使用默认值: 3.在读取数据的线程中读取数据,首先使用pthread_mutex_lock函数对互斥量A进行加锁

一起talk C栗子吧(第一百一十二回:C语言实例--线程同步概述)

各位看官们,大家好.上一回中咱们说的是线程间通信的样例,这一回咱们说的样例是:线程同步.闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,提到同步.我想大家都不陌生,由于我们在前面章回中介绍过进程同步的内容. 大家都知道线程是轻量级的进程,尽管线程不像进程一样须要专门的通信机制,可是线程须要专门的同步机制. 今天我们来介绍一下线程同步的内容. 同步的含义对于进程和线程是同样的.仅仅是进程和线程实现同步的方式不同样.关于同步的含义,我们就不做具体的介绍了,假设大家忘记了,能够点击这里查看

linux 线程的同步 三 (信号量的使用)

信号量.同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已.但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆,关于用于进程间通信的信号量的详细介绍可以参阅我的另一篇博文:Linux进程间通信——使用信号量.相似地,线程同步是控制线程执行和访问临界区域的方法. 一.什么是信号量 线程的信号量与进程间通信中使用的信号量的概念是一样,它是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作.如果一个程序中有多个线

JAVA线程同步 (三)信号量

一个信号量有且仅有3种操作,且它们全部是原子的:初始化.增加和减少 增加可以为一个进程解除阻塞: 减少可以让一个进程进入阻塞. 信号量维护一个许可集,若有必要,会在获得许可之前阻塞每一个线程:           //从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞.           acquireUninterruptibly(int permits){} 每一个release()添加一个许可,从而可能释放一个正在阻塞的获取者. Semaphore只对可用许可的号码进行计数,并