也属于线程同步的一种方式
信号量 Semaphore
定义:
有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。
目的:
类似计数器,常用在多线程同步任务上,信号量可以在当前线程某个任务完成后,通知别的线程,再进行别的任务。
分类:
- 二值信号量:信号量的值只有 0 和 1,这和互斥量很类似,若资源被锁住,信号量的值为 0,若资源可用,则信号量的值为 1;
- 计数信号量:信号量的值在 0 到一个大于 1 的限制值之间,该计数表示可用的资源的个数。
信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为 1 就变成互斥锁 Mutex,即同时只能有一个任务可以访问信号量保护的共享资源
函数使用
库 首先需要 include <semaphore.h> 这个库,没啥好说的,除非你自己实现内部函数。和互斥锁一样也是四大金刚。 sem_init 简述:_创建信号量_ 第一个参数:指向的信号对象 第二个参数:控制信号量的类型,如果其值为 0,就表示信号量是当前进程的局部信号量,否则信号量就可以在多个进程间共享 第三个参数:信号量 sem 的初始值 返回值:success 为 0,failure 为 - 1
| int sem_init(sem_t *sem, int pshared, unsigned int value); |
sem_post 简述:信号量的值加 1 第一个参数:信号量对象 返回值:success 为 0,failure 为 - 1
| int sem_post(sem_t *sem); |
sem_wait 简述:信号量的值加 - 1 第一个参数:信号量对象 返回值:success 为 0,failure 为 - 1
| int sem_wait(sem_t *sem); |
sem_destroy 简述:用完记得销毁哦~ 第一个参数:信号量对象 返回值:success 为 0,failure 为 - 1
| int sem_destroy(sem_t *sem); |
举例
说明:你可以进行三个下载任务,但是最多选择同时执行二个(创建两个线程)。直接看 main 函数即可,信号量的逻辑都在里面,在实际代码中最好,所有的线程和信号量的创建、释放都要进行校验,这里为了方便阅读,减少代码行数,就不进行校验了。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <windows.h>
#define MAXNUM 2
sem_t semDownload;
pthread_t a_thread, b_thread, c_thread;
int g_phreadNum = 1;
void InputInfo(void)
{
printf("****************************************\n");
printf("*** which task you want to download? ***\n");
printf("*** you can enter [1-3],[0] is done ***\n");
printf("****************************************\n");
}
void *func1(void *arg)
{
//等待信号量的值>0
sem_wait(&semDownload);
printf("============== Downloading Task 1 ============== \n");
Sleep(5000);
printf("============== Finished Task 1 ============== \n");
g_phreadNum--;
//等待线程结束
pthread_join(a_thread, NULL);
}
void *func2(void *arg)
{
sem_wait(&semDownload);
printf("============== Downloading Task 2 ============== \n");
Sleep(3000);
printf("============== Finished Task 2 ============== \n");
g_phreadNum--;
pthread_join(b_thread, NULL);
}
void *func3(void *arg)
{
sem_wait(&semDownload);
printf("============== Downloading Task 3 ============== \n");
Sleep(1000);
printf("============== Finished Task 3 ============== \n");
g_phreadNum--;
pthread_join(c_thread, NULL);
}
int main()
{
int taskNum;
InputInfo();
while (scanf("%d", &taskNum) != EOF) {
//输入0,判断是否正常退出
if (taskNum == 0 && g_phreadNum <= 1) {
break;
}
if (taskNum == 0){
printf("Can not quit, casue count of threads is [%d]\n", g_phreadNum - 1);
}
//初始化信号量
sem_init(&semDownload, 0, 0);
printf("your choose Downloading Task [%d]\n", taskNum);
//线程数超过2个则不下载
if (g_phreadNum > MAXNUM) {
printf("!!! You've reached a limit on the number of threads !!!\n");
continue;
}
//用户选择下载Task
switch (taskNum)
{
case 1:
//创建线程1
pthread_create(&a_thread, NULL, func1, NULL);
//信号量+1,进而触发fun1的任务
sem_post(&semDownload);
//总线程数+1
g_phreadNum++;
break;
case 2:
pthread_create(&b_thread, NULL, func2, NULL);
sem_post(&semDownload);
g_phreadNum++;
break;
case 3:
pthread_create(&c_thread, NULL, func3, NULL);
sem_post(&semDownload);
g_phreadNum++;
break;
default:
printf("!!! eroor task [%d] !!!\n", taskNum);
break;
}
}
//销毁信号量
sem_destroy(&semDownload);
return 0;
}
图解
|