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

运行结果:

相关推荐
凤枭香9 分钟前
Python Selenium介绍(二)
开发语言·爬虫·python·selenium
疯狂吧小飞牛10 分钟前
C语言解析命令行参数
c语言·开发语言
z2023050814 分钟前
linux之调度管理(13)- wake affine 唤醒特性
java·开发语言
AI人H哥会Java15 分钟前
【JAVA】Java高级:Java网络编程——TCP/IP与UDP协议基础
java·开发语言
小白要加油哈28 分钟前
Lua--1.基础知识
开发语言·junit·lua
网络安全Ash41 分钟前
企业网络安全之OPENVPN
开发语言·网络·php
xcLeigh43 分钟前
C# Winform贪吃蛇小游戏源码
开发语言·c#
易辰君1 小时前
【Python爬虫实战】深入解析 Scrapy:从阻塞与非阻塞到高效爬取的实战指南
开发语言·python
荒-漠1 小时前
php CURL请求502
开发语言·php
桃园码工1 小时前
第一章:Go 语言概述 2.安装和配置 Go 开发环境 --Go 语言轻松入门
开发语言·后端·golang