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.......一直循环.....

代码:

#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

gcc thread.c -o thread -lpthread

运行结果:

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-08 09:00:06       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-08 09:00:06       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-08 09:00:06       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-08 09:00:06       18 阅读

热门阅读

  1. 软件定制开发与标准化产品的比较及选择

    2023-12-08 09:00:06       39 阅读
  2. 游戏架构之面向对象模型和组件模型

    2023-12-08 09:00:06       35 阅读
  3. Nmap脚本的基础知识

    2023-12-08 09:00:06       33 阅读
  4. 52. govaluate使用

    2023-12-08 09:00:06       39 阅读
  5. C#使用Matrix类对Dicom图像的放缩

    2023-12-08 09:00:06       44 阅读
  6. LeetCode-15. 三数之和

    2023-12-08 09:00:06       43 阅读
  7. ElasticSearch中的分析器是什么?

    2023-12-08 09:00:06       38 阅读
  8. R语言进行正态分布检验

    2023-12-08 09:00:06       38 阅读
  9. Mongodb中的ObjectId

    2023-12-08 09:00:06       34 阅读
  10. 看图学源码之 CopyOnWriteArraySet源码分析

    2023-12-08 09:00:06       30 阅读
  11. ZooKeeper学习一

    2023-12-08 09:00:06       27 阅读
  12. iSoftBook、Jira、GitLab、TAPT研发管理平台的比较

    2023-12-08 09:00:06       48 阅读