三个线程,依次打印

时间:2022-09-28 18:30:53

编程实现三个线程ABC,并让它们顺次打印ABC

来源:牛客网的BAT经典面试题

思路:设置三个信号量:S1, S2, S3,S2由S1 post,S3由S2 post, S1由S3 post,由A线程先开始打印,其他线程必然在等待信号量,所以三个线程一定会按照信号量的顺序来打印。

注意vs 2015中多线程使用要调用windows下的API。一般在Linux下用操作系统中讲到的POSIX那一套。

代码实现:

/*
* 3个线程逐个执行打印,线程依次控制下一个线程的信号量
*/

#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include <pthread.h>

sem_t sem_id1, sem_id2, sem_id3;

void * func1(void *);
void * func2(void *);
void * func3(void *);

int main()
{
//初始化3个信号量
sem_init(&sem_id1, 0, 1);
sem_init(&sem_id2, 0, 0);
sem_init(&sem_id3, 0, 0);
// 创建3个线程
pthread_t pthread_id1, pthread_id2, pthread_id3;
pthread_create(&pthread_id1, NULL, &func1, NULL);
pthread_create(&pthread_id2, NULL, &func2, NULL);
pthread_create(&pthread_id3, NULL, &func3, NULL);
// 主进程等待线程执行完毕
pthread_join(pthread_id1, NULL);
pthread_join(pthread_id2, NULL);
pthread_join(pthread_id3, NULL);

return 0;
}

void * func1(void *)
{
// 阻塞等待信号量1,等其>0时,信号量--
sem_wait(&sem_id1);
printf("A\n");
// 信号量2++
sem_post(&sem_id2);
}

void * func2(void *)
{
// 阻塞等待线程1中将信号量2++
sem_wait(&sem_id2);
printf("B\n");
// 信号量3++
sem_post(&sem_id3);
}

void * func3(void *)
{
// 阻塞等待线程2将信号量3++
sem_wait(&sem_id3);
printf("C\n");
// 信号量1++
sem_post(&sem_id1);
}

// compile and run
// 编译选项要加-pthread,否则报错说找不到线程函数
g++ -pthread thread_print_in_order.cpp -o test
./test

sem_wait sem_post
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。
它的原型为:extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,为0时只能为当前进程的所有线程共享;value给出了信号量的初始值。  

函数sem_post( sem_t *sem)用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  

函数sem_wait( sem_t *sem)被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait (sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。函数sem_destroy(sem_t *sem)用来释放信号量sem。

若是不使用信号量,则还可以创建一个线程,在该线程中继续创建一个线程,递归的调用下去,等待每个线程返回,不断打印出顺序值。

代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>

void * func1(void *);
void * func2(void *);
void * func3(void *);

int main()
{
pthread_t pthread_id1;
pthread_create(&pthread_id1, NULL, &func1, NULL);
pthread_join(pthread_id1, NULL);

return 0;
}

void * func1(void *)
{
pthread_t pthread_id1;
pthread_create(&pthread_id1, NULL, &func2, NULL);
pthread_join(pthread_id1, NULL);
// func2执行完才会打印C
printf("C\n");
}

void * func2(void *)
{
pthread_t pthread_id2;
pthread_create(&pthread_id2, NULL, &func3, NULL);
pthread_join(pthread_id2, NULL);
// func3执行完才会打印B
printf("B\n");
}

void * func3(void *)
{
printf("A\n");
}