Linux 线程——信号量

题目:编写代码实现编写一个程序,开启三个线程,这三个线程的ID分别是A,B,C,每个线程将自己的ID在屏幕上打印10遍,要求输出必须按照ABC的顺序显示,如:ABCABCABC...

思路:创建三个ID分别为ABC的线程,定义三个信号量,利用信号量减值0时会堵塞这一特点来实现ABC顺序显示。具体是给A一个信号量,B和C设初始信号量为0,当A申请信号量,信号量减1成0,信号量A堵塞,这时对B释放信号量,开始执行线程B,当B也申请信号量减一变0造成堵塞时,C释放信号量,执行线程C.......一直循环.....

代码:

cpp 复制代码
#include<stdio.h>
#include<pthread.h>
#include<errno.h>
#include<semaphore.h>
#include<string.h>
pthread_t A,B,C;     //获取线程ID 
pthread_mutex_t lock;  //互斥锁 
sem_t sem1,sem2,sem3;  //定义信号量 
/*创建线程函数的目的是因为 线程创建函数pthread_create的第三个参数是一个函数指针*/ 
void *A_handler(void *arg)     //线程A函数 
{
    int  count = *((int *)arg);//线程执行次数,通过线程创建函数pthread_create的第四个参数获取 
   	while(count > 0)
    {
    	sem_wait(&sem1);        //为信号量sem1申请信号量,若申请成功信号量值减1 
    	//pthread_mutex_lock(&lock); //上锁 
      	printf("A...\n"); //申请成功输出A,A为线程A标识符 
        sleep(1);         //休眠1秒 
        count--;			//线程A执行次数减1 
        //pthread_mutex_unlock(&lock);//解锁 
        sem_post(&sem2); //释放信号量,信号量值加一。此操作是为了防止sem1将信号量申请完造成堵塞,因此这里让sem2释放信号量,始终保留一定信号量。 
	}
	pthread_exit("A...exit");//终止调用线程A 
}
void *B_handler(void *arg)  //线程B函数 
{
	int count = *((int *)arg); //线程B执行次数 通过线程创建函数pthread_create的第四个参数arg获取 
	
	while(count > 0)
	{
		sem_wait(&sem2);     //为sem2申请信号量,信号量 值减一 
		//pthread_mutex_lock(&lock);//上锁 
		printf("B...\n");//打印B申请成功的提示 
		sleep(1);//休眠1秒 
		count--;//线程B执行次数减1,直到不大于0,不再申请 
		//pthread_mutex_unlock(&lock);
		sem_post(&sem3);//同线程A函数,以释放信号量sem3来满足信号量sem2 申请所需的信号量,防止堵塞 
	}
	pthread_exit("B...exit");//终止调用线程B 
}
void *C_handler(void *arg)//线程C函数 
{
	int count = *((int *)arg);//线程C执行次数 通过线程创建函数pthread_create的第四个参数arg获取 
	
	while(count > 0)
	{
		sem_wait(&sem3);//为sem3申请信号量,信号量 值减一 
		//pthread_mutex_lock(&lock);//上锁 
		printf("C...\n");//输出提示,表示申请成功 
		sleep(1);//休眠,也可以说是延时 
		count--;// 线程C执行次数减1,直到不大于0,不再申请
		//pthread_mutex_unlock(&lock);
		sem_post(&sem1);//同线程A和B函数,以释放信号量sem1来满足信号量sem3申请所需的信号量,防止堵塞 
	}
	pthread_exit("C...exit");//终止线程C调用,打印终止字符提示 
}
int main(int argc,const char *argv[]) //参数用于对运行成功后传入终端输入参数的个数和名称 
{
	int arg1 = 10; //线程A执行次数 
	int arg2 = 10; //线程B执行次数 
	int arg3 = 10;//线程C执行次数 
	void *retval;  //非空指针,用于pthread_join函数返回线程标识 
	 /*信号量初始化,参数1为信号量标识符,参数2有两个值,为0时表示信号量用于同一进程多线程之间,非0时表示信号量由于进程与进程之间  参数3为信号量初始值 */
	 
	/*三个信号量分别设置1,0,0;基此循环*/ 
	if(sem_init(&sem1,0,1)<0)  //信号量sem1初始化 
	{                         
		perror("sem_init error");
	}
	
	if(sem_init(&sem2,0,0)<0)//信号量sem2初始化 
	{
		perror("sem_init error");
	}
	
	if(sem_init(&sem3,0,0)<0)//信号量sem3初始化 
	{
		perror("sem_init error");
	}
	
	/*线程创建函数pthread_create,共有四个参数,参数1为线程标识符,也叫线程ID;参数2指向一个结构体,为NULL时表示采用默认属性,参数3指向线程函数,参数4为参数3指向的函数传参。*/ 
	if(pthread_create(&A,NULL,A_handler,(void *)&arg1) != 0)  //创建ID为A,默认属性,指向线程函数A,传入参数(执行次数)为 arg1的线程 
	{
		perror("pthread_createA error");
		
	}
	if(pthread_create(&B,NULL,B_handler,(void *)&arg2) != 0)//创建ID为B,默认属性,指向线程函数B,传入参数(执行次数)为 arg2的线程 
	{
		perror("pthread_createB error");
		
	}
	if(pthread_create(&C,NULL,C_handler,(void *)&arg3) != 0)//创建ID为C,默认属性,指向线程函数C,传入参数(执行次数)为 arg3的线程 
	{
		perror("pthread_createC error");
		
	}
	/*pthread_join函数用于线程终止后返回非空指针retval保存的线程标识符 */
	pthread_join(A,&retval);           //返回线程A的标识符
	printf("%s\n",(char *)retval);     //输出线程标识符 
	
	pthread_join(B,&retval);
	printf("%s\n",(char *)retval);
	
	pthread_join(C,&retval);
	printf("%s\n",(char *)retval);
	
	sem_destroy(&sem1);  //摧毁信号量 
	sem_destroy(&sem2);
	sem_destroy(&sem3);
	
	//pthread_mutex_destory(&lock);
	return 0;
}

编译时要加后缀 -lpthread

cs 复制代码
gcc thread.c -o thread -lpthread

运行结果:

相关推荐
不是万能的豆学长4 小时前
filetidy 文件整理助手:一键归类 + 规范重命名(Python 零依赖单文件工具)
大数据·开发语言·python·技术美术
懂点Tech8 小时前
ctfshow MISC入门图片篇(信息附加):misc41解题思路
开发语言·python
catchadmin9 小时前
PHP 8.7 协程新提案 让跨协程代码共享请求身份
开发语言·php
念何架构之路10 小时前
go-grpc设计思想
开发语言·后端·golang
酷炫码神10 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript
Elastic 中国社区官方博客11 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn18811 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn12 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
传奇开心果编程12 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用
qetfw13 小时前
Bash 变量:export、位置参数与默认值展开验证
linux·开发语言·chrome·bash