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
运行结果: