有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。
类似计数器,常用在多线程同步任务上,信号量可以在当前线程某个任务完成后,通知别的线程,再进行别的任务。
二值信号量:信号量的值只有0和1,这和互斥量很类似,若资源被锁住,信号量的值为0,若资源可用,则信号量的值为1;
计数信号量:信号量的值在0到一个大于1的限制值之间,该计数表示可用的资源的个数。
信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为1就变成互斥锁Mutex,即同时只能有一个任务可以访问信号量保护的共享资源
首先需要include
这个库,没啥好说的,除非你自己实现内部函数。和互斥锁一样,也是四大金刚。(编译的时候需要加上-lpthread
)
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem_post
第一个参数:指向的信号对象
第二个参数:控制信号量的类型,如果其值为0,就表示信号量是当前进程的局部信号量,否则信号量就可以在多个进程间共享
第三个参数:信号量sem的初始值
返回值:success为0,failure为-1
int sem_post(sem_t *sem);
第一个参数:信号量对象
返回值:success为0,failure为-1
int sem_wait(sem_t *sem);
第一个参数:信号量对象
返回值:success为0,failure为-1
int sem_destroy(sem_t *sem);
第一个参数:信号量对象
返回值:success为0,failure为-1
(我对原作者的代码进行了一些改造)
#include
#include
#include
//#include
#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)
{
int ret;
//等待信号量的值>0
ret = sem_wait(&semDownload);
if(ret != 0)
{
printf("error, sem_wait failed\n");
}
printf("============== Downloading Task 1 ============== \n");
sleep(5);
printf("============== Finished Task 1 ============== \n");
g_phreadNum--;
//等待线程结束
//pthread_join(a_thread, NULL);
}
void *func2(void *arg)
{
int ret;
ret = sem_wait(&semDownload);
if(ret != 0)
{
printf("error, sem_wait failed\n");
}
printf("============== Downloading Task 2 ============== \n");
sleep(3);
printf("============== Finished Task 2 ============== \n");
g_phreadNum--;
//pthread_join(b_thread, NULL);
}
void *func3(void *arg)
{
int ret;
ret = sem_wait(&semDownload);
if(ret != 0)
{
printf("error, sem_wait failed\n");
}
printf("============== Downloading Task 3 ============== \n");
sleep(1);
printf("============== Finished Task 3 ============== \n");
g_phreadNum--;
//pthread_join(c_thread, NULL);
}
int main()
{
int ret;
int taskNum;
InputInfo();
//初始化信号量
ret = sem_init(&semDownload, 0, 0);
if(ret != 0)
{
printf("error, sem_init failed\n");
}
while (scanf("%d", &taskNum) != EOF) {
//输入0,判断是否正常退出
if (taskNum == 0)
{
if (g_phreadNum <= 1)
{
break;
}
else
{
printf("Can not quit, casue count of threads is [%d]\n", g_phreadNum - 1);
}
}
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的任务
ret = sem_post(&semDownload);
if(ret != 0)
{
printf("error, sem_post failed\n");
}
//总线程数+1
g_phreadNum++;
break;
case 2:
pthread_create(&b_thread, NULL, func2, NULL);
ret = sem_post(&semDownload);
if(ret != 0)
{
printf("error, sem_post failed\n");
}
g_phreadNum++;
break;
case 3:
pthread_create(&c_thread, NULL, func3, NULL);
ret = sem_post(&semDownload);
if(ret != 0)
{
printf("error, sem_post failed\n");
}
g_phreadNum++;
break;
default:
printf("!!! eroor task [%d] !!!\n", taskNum);
break;
}
}
//销毁信号量
sem_destroy(&semDownload);
if(ret != 0)
{
printf("error, sem_destroy failed\n");
}
return 0;
}
CentOS编译运行结果:
[root@localhost 20220816]# ./a.out
****************************************
*** which task you want to download? ***
*** you can enter [1-3],[0] is done ***
****************************************
1
your choose Downloading Task [1]
============== Downloading Task 1 ==============
============== Finished Task 1 ==============
2
your choose Downloading Task [2]
============== Downloading Task 2 ==============
3
your choose Downloading Task [3]
============== Downloading Task 3 ==============
============== Finished Task 2 ==============
4============== Finished Task 3 ==============
your choose Downloading Task [4]
!!! eroor task [4] !!!
5
your choose Downloading Task [5]
!!! eroor task [5] !!!
1
your choose Downloading Task [1]
============== Downloading Task 1 ==============
2
your choose Downloading Task [2]
============== Downloading Task 2 ==============
3
your choose Downloading Task [3]
!!! You've reached a limit on the number of threads !!!
============== Finished Task 1 ==============
============== Finished Task 2 ==============
4
your choose Downloading Task [4]
!!! eroor task [4] !!!
简介:一个线程生产,另一个线程消费,线程A生产完后立马给线程B发信号,线程B收到后立即回应线程A,告诉它我收到了,发送100000次
(test_semaphore_1_1.c)
#include
#include
#include
#include "unistd.h"
#include
#define printf(format, ...) \
do { \
char str[1024] = {0}; \
struct timeval tv; \
struct tm* t; \
gettimeofday(&tv, NULL); \
t = localtime(&tv.tv_sec); \
sprintf(str,"[%04d-%02d-%02d %02d:%02d:%02d.%03ld] ", \
1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, \
t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); \
printf("%s", str); \
printf("#%d "format, __LINE__, ##__VA_ARGS__); \
} while (0)
#define LIM (100000)
sem_t sem, sem_R;
int count = 0;
int count_R = 0;
void* f_producer(void *arg)
{
sleep(1);
int ret;
while(1)
{
printf("[%s] produce start\n", __FUNCTION__);
//信号量+1,进而触发fun1的任务
printf("[%s] produce finish, sem_post\n", __FUNCTION__);
ret = sem_post(&sem);
if(ret != 0)
{
printf("[%s] error, sem_post failed\n", __FUNCTION__);
break;
}
count++;
printf("\n[%s] count = %d\n", __FUNCTION__, count);
if(count == LIM)
{
printf("[%s] break\n", __FUNCTION__);
break;
}
printf("[%s] waiting for sem_R\n", __FUNCTION__);
ret = sem_wait(&sem_R);
if(ret != 0)
{
printf("[%s] error, sem_wait failed\n", __FUNCTION__);
break;
}
printf("[%s] received sem_R\n", __FUNCTION__);
}
}
void* f_consumer(void *arg)
{
sleep(1);
int ret;
while(1)
{
printf("[%s] waiting for sem\n", __FUNCTION__);
ret = sem_wait(&sem);
if(ret != 0)
{
printf("error, sem_wait failed\n");
break;
}
printf("[%s] received sem\n", __FUNCTION__);
count_R++;
printf("\n[%s] count_R = %d\n", __FUNCTION__, count_R);
if(count_R == LIM)
{
printf("[%s] break\n", __FUNCTION__);
break;
}
printf("[%s] return start\n", __FUNCTION__);
ret = sem_post(&sem_R);
if(ret != 0)
{
printf("[%s] error, sem_post failed\n", __FUNCTION__);
break;
}
}
}
int main()
{
int ret;
pthread_t consumer, producer;
//初始化信号量
ret = sem_init(&sem, 0, 0);
if(ret != 0)
{
printf("error, sem_init failed\n");
}
//创建线程
pthread_create(&producer, NULL, f_producer, NULL);
pthread_create(&consumer, NULL, f_consumer, NULL);
ret = pthread_join(producer, NULL);
if(ret != 0)
{
printf("error, join failed, ret = [%d]\n", ret);
}
ret = pthread_join(consumer, NULL);
if(ret != 0)
{
printf("error, join failed, ret = [%d]\n", ret);
}
//销毁信号量
sem_destroy(&sem);
if(ret != 0)
{
printf("error, sem_destroy failed\n");
}
return 0;
}
编译运行:
[root@localhost 20220817]# gcc test_semaphore_1_1.c -lpthread
[root@localhost 20220817]# ./a.out
结果:
总共只花费了10秒钟就跑完了,且无信号丢失,还是很稳定的(比那个啥互斥锁+条件变量好用多了lll…)
(略,后更。。。)
这用来做线程间通知,不比锁加条件变量好用多了啊!!!!那个一大堆,还挺麻烦的,,,,,,