多线程p3_信号量

也属于线程同步的一种方式

信号量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;
}

图解

写错了,有箭头指向的字,把进程改为线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiujiaHuan13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值