目录
题目
请在linux 利用c语言编程实现两个线程按照顺序依次输出”ABABABAB......" (信雅达)例如a线程输出”A”之后b线程输出”B”,然后a线程输出“A”,再b线程输出”B”,之后往复循环。
信号量实现
思路分析
一、整体功能概述
创建一个子线程执行
funB
函数,同时在主线程中进行一系列操作,通过两个信号量sem0
和sem1
来协调两个执行路径的执行顺序,使得它们交替输出字符A
和B
。二、主要函数和变量分析
funB
函数:
- 这是子线程执行的函数。
- 在一个无限循环中,首先调用
sem_wait(&sem0)
等待信号量sem0
,这意味着子线程会在此处阻塞,直到信号量sem0
的值大于 0。- 当信号量
sem0
可用时,输出字符B
,并使用fflush(NULL)
刷新输出缓冲区,确保字符立即输出。- 然后调用
sleep(1)
暂停子线程执行 1 秒钟。- 最后调用
sem_post(&sem1)
,将信号量sem1
的值加 1,以通知主线程可以继续执行。
main
函数:
- 首先定义了一个
pthread_t
类型的变量tid
,用于存储子线程的标识符。- 接着调用
pthread_create(&tid, NULL, funB, NULL)
创建一个子线程,并传入funB
函数作为子线程的执行函数。如果创建子线程失败,会输出错误信息并返回-1
。- 然后分别初始化两个信号量
sem0
和sem1
。sem_init(&sem0, 0, 0)
将信号量sem0
初始化为 0,表示初始状态下子线程会在等待这个信号量。sem_init(&sem1, 0, 1)
将信号量sem1
初始化为 1,表示初始状态下主线程可以立即获取这个信号量并开始执行。- 在一个无限循环中,主线程首先调用
sem_wait(&sem1)
等待信号量sem1
,当信号量sem1
可用时,输出字符A
,刷新输出缓冲区,然后调用sem_post(&sem0)
,将信号量sem0
的值加 1,通知子线程可以继续执行。三、执行流程分析
- 程序开始执行,在
main
函数中创建子线程和初始化信号量。- 由于初始状态下信号量
sem0
的值为 0,子线程会在sem_wait(&sem0)
处阻塞等待。- 主线程由于初始状态下信号量
sem1
的值为 1,可以立即通过sem_wait(&sem1)
,然后输出字符A
,并将信号量sem0
的值加 1。- 子线程被唤醒,执行输出字符
B
,暂停 1 秒,然后将信号量sem1
的值加 1。- 主线程再次被唤醒,重复上述过程,如此循环交替输出字符
A
和B
。四、应用场景和注意事项
- 应用场景:这种同步机制可以用于需要两个不同执行路径相互协作、交替执行任务的情况,例如在多线程环境下协调不同的操作顺序。
- 注意事项:
- 确保在合适的时候销毁信号量,以避免资源泄漏。
- 考虑在程序退出时正确地终止子线程和主线程,避免出现死锁或资源未释放的情况。
- 注意多线程编程中的竞争条件和数据一致性问题,确保对共享资源的访问是正确同步的。
代码
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#include <unistd.h>
sem_t sem0, sem1;
void *funB(void *arg)
{
while (1)
{
sem_wait(&sem0);
printf("B");
fflush(NULL);
sleep(1);
sem_post(&sem1);
}
}
int main(int argc, char const *argv[])
{
pthread_t tid;
if (pthread_create(&tid, NULL, funB, NULL) != 0)
{
perror("pthread err");
return -1;
}
if (sem_init(&sem0, 0, 0) != 0)
{
perror("init0 err");
return -1;
}
if (sem_init(&sem1, 0, 1) != 0)
{
perror("init1 err");
return -1;
}
while (1)
{
sem_wait(&sem1);
printf("A");
fflush(NULL);
sem_post(&sem0);
}
return 0;
}
条件变量实现
思路分析
一、整体功能概述
通过互斥锁(
pthread_mutex_t
)和条件变量(pthread_cond_t
)的组合,使得线程funA
和线程funB
能够按照特定的顺序交替执行输出操作,分别输出字符A
和B
。二、主要函数和变量分析
funA
函数:
- 这个函数是线程
tid1
执行的函数。- 首先使用
sleep(2)
暂停执行 2 秒,模拟一些初始化操作或等待其他资源准备好。- 在一个无限循环中,每次循环先使用
sleep(1)
暂停 1 秒。- 然后获取互斥锁
lock
,接着输出字符A
,并使用fflush(NULL)
刷新输出缓冲区确保字符立即输出。- 调用
pthread_cond_signal(&cond)
发送信号,通知正在等待条件变量cond
的线程(即funB
所在的线程)。- 最后释放互斥锁
lock
。- 最后通过
pthread_exit(NULL)
退出线程。
funB
函数:
- 这个函数是线程
tid2
执行的函数。- 首先使用
sleep(1)
暂停执行 1 秒,可能是为了与线程funA
的执行时间有所区分。- 在一个无限循环中,首先获取互斥锁
lock
。- 然后调用
pthread_cond_wait(&cond, &lock)
,这个函数会原子地释放互斥锁lock
,并等待条件变量cond
被触发。当条件变量被触发时,函数会重新获取互斥锁并继续执行。- 接着输出字符
B
,并刷新输出缓冲区。- 最后释放互斥锁
lock
。- 在函数结束处通过
putchar('\n')
输出一个换行符,然后通过pthread_exit(NULL)
退出线程。
main
函数:
- 首先定义了两个
pthread_t
类型的变量tid1
和tid2
,用于存储两个线程的标识符。- 接着初始化互斥锁
lock
和条件变量cond
,分别使用pthread_mutex_init(&lock, NULL)
和pthread_cond_init(&cond, NULL)
。- 使用
pthread_create(&tid1, NULL, funA, NULL)
创建线程tid1
,并传入funA
函数作为线程执行的函数。如果创建失败,会输出错误信息并返回-1
。- 同样使用
pthread_create(&tid2, NULL, funB, NULL)
创建线程tid2
,并传入funB
函数作为线程执行的函数。如果创建失败,会输出错误信息并返回-1
。- 然后使用
pthread_join(tid1, NULL)
和pthread_join(tid2, NULL)
分别等待线程tid1
和tid2
结束,确保程序在所有线程都执行完毕后才退出。三、执行流程分析
- 程序开始执行,在
main
函数中初始化互斥锁和条件变量,并创建两个线程。- 线程
tid1
(执行funA
函数)先暂停 2 秒,然后进入无限循环。每次循环暂停 1 秒后,获取互斥锁,输出字符A
,发送条件变量信号,然后释放互斥锁。- 线程
tid2
(执行funB
函数)先暂停 1 秒,然后进入无限循环。在循环中,获取互斥锁后,等待条件变量被触发。一旦条件变量被触发,输出字符B
,然后释放互斥锁。- 由于线程
tid1
先执行并发送条件变量信号,线程tid2
在等待条件变量后被唤醒并输出字符B
。然后两个线程交替执行,不断输出A
和B
。- 最后,当程序需要退出时,在
main
函数中等待两个线程结束,然后清理资源并退出程序。四、应用场景和注意事项
- 应用场景:这种同步机制适用于需要两个或多个线程按照特定顺序执行任务的情况,例如生产者 - 消费者问题、线程间的协作和同步等。
- 注意事项:
- 确保在合适的时候销毁互斥锁和条件变量,以避免资源泄漏。
- 注意互斥锁和条件变量的正确使用顺序,避免出现死锁或错误的同步行为。
- 考虑在多线程环境下可能出现的竞争条件和数据一致性问题,确保对共享资源的访问是正确同步的。
代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t lock;
pthread_cond_t cond;
void *funA(void *arg)
{
sleep(2);
while (1)
{
sleep(1);
pthread_mutex_lock(&lock);
printf("A");
fflush(NULL);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
pthread_exit(NULL);
}
void *funB(void *arg)
{
sleep(1);
while (1)
{
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
printf("B ");
fflush(NULL);
pthread_mutex_unlock(&lock);
}
putchar('\n');
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
pthread_t tid1, tid2;
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&lock, NULL);
if (pthread_create(&tid1, NULL, funA, NULL) < 0)
{
perror("tid1 err");
return -1;
}
if (pthread_create(&tid2, NULL, funB, NULL) < 0)
{
perror("tid1 err");
return -1;
}
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}