目录
题目
用信号量实现输入输出quit结束
思路
一、整体功能概述
这段 C 语言代码使用信号量和线程实现了两个执行路径之间的同步通信,一个路径从终端读取输入,另一个路径打印输入内容,当输入为 “quit” 时,两个路径都结束。
二、主要函数和变量分析
main
函数:
- 定义了一个线程标识符
tid
。- 初始化了两个信号量
sem1
和sem2
。其中sem1
初始值为 0,sem2
初始值为 1。这意味着一开始sem2
的资源可用,而sem1
的资源需要等待被释放。- 使用
pthread_create
创建一个子线程,执行handler_thread
函数。- 在一个无限循环中,首先等待信号量
sem2
,表示等待资源可用以进行输入操作。然后从终端读取输入存储到字符数组s
中。接着释放信号量sem1
,通知子线程可以进行打印操作。如果输入为 “quit”,则跳出循环。
handler_thread
函数:
- 这是子线程执行的函数。在一个无限循环中,首先等待信号量
sem1
,表示等待输入完成以进行打印操作。如果输入为 “quit”,则跳出循环。然后打印输入内容,并释放信号量sem2
,通知主线程可以进行下一次输入操作。三、执行流程分析
- 程序开始执行,在
main
函数中初始化信号量和创建子线程。- 由于初始状态下
sem2
的资源可用,主线程首先进入循环,等待sem2
,然后进行输入操作。- 输入完成后,主线程释放
sem1
,子线程被唤醒,因为子线程一直在等待sem1
。- 子线程读取输入内容并打印,如果不是 “quit”,则释放
sem2
,通知主线程可以进行下一次输入操作。- 如此循环,直到输入为 “quit”,此时主线程和子线程都会跳出各自的循环,程序结束。
四、应用场景和注意事项
应用场景:
- 适用于需要两个不同执行路径相互协作、按照特定顺序执行任务的情况,例如一个路径负责收集数据,另一个路径负责处理和输出数据。
- 可以用于实现简单的生产者 - 消费者模型,主线程作为生产者提供输入,子线程作为消费者进行处理和输出。
注意事项:
- 确保在程序结束时正确地销毁信号量,以避免资源泄漏。
- 考虑在多线程环境下可能出现的竞争条件和数据一致性问题,虽然这里通过信号量进行了一定程度的同步,但在更复杂的场景中可能需要更严格的同步机制。
- 注意输入的合法性和安全性,避免输入导致程序出现异常或安全漏洞。
代码
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
char s[32];
sem_t sem1; //信号量对象
sem_t sem2;
void *handler_thread(void *arg)
{
while (1)
{
//申请资源 sem1
sem_wait(&sem1);
if (strcmp(s, "quit") == 0)
break;
printf("%s\n", s);
//释放资源sem2
sem_post(&sem2);
}
return NULL;
}
int main(int argc, char const *argv[])
{
pthread_t tid;
//初始化信号量
if (sem_init(&sem1, 0, 0) != 0)
{
perror("sem_init err");
return -1;
}
if (sem_init(&sem2, 0, 1) != 0)
{
perror("sem_init err");
return -1;
}
if (pthread_create(&tid, NULL, handler_thread, NULL) != 0)
{
perror("err");
return -1;
}
while (1)
{
//申请资源sem2
sem_wait(&sem2);
scanf("%s", s);
//释放资源sem1
sem_post(&sem1);
if (strcmp(s, "quit") == 0)
break;
}
}