目录
一、实验目的
1、深入理解线程模型相关概念;
2、掌握线程相关的数据结构及常用的函数。
二、实验内容
线程A向终端打印字符 “1”,线程B向终端打印字符 “2”。要求使用 POSIX 线程和信号量实现以下功能:向终端打印 “1 2 1 2”。
三、实验环境
虚拟机软件:VMware 16 Pro
Linux操作系统版本:CentOS-7-64位
四、参考代码
#include<semaphore.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
void* funA(void*);
void* funB(void*);
sem_t sem1,sem2;
int main(void){
pthread_t tid1,tid2;
int i=0;
sem_init(&sem1,0,1);
sem_init(&sem2,0,0);
for(i=0;i<2;i++){
pthread_create(&tid1,NULL,funA,NULL);
pthread_create(&tid2,NULL,funB,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
}
printf("\n");
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}
void* funA(void* arg){
sem_wait(&sem1);
printf("1\t");
sem_post(&sem2);
return NULL;
}
void* funB(void* arg){
sem_wait(&sem2);
printf("2\t");
sem_post(&sem1);
return NULL;
}
五、实验步骤
步骤1. 编辑源代码test7.c
源代码test7.c内容见上述参考代码。
mkdir test7
cd test7
vim test7.c
步骤2. 编译源代码test7.c
gcc test7.c -o test7 -g -pthread
步骤3. 运行可执行程序test7
./test7
步骤4. 进一步调试源代码test7.c
实现以上的Linux的C程序,并做如下改动:
(1)在funA内,把原来输出的“1
”改成输出自己的学号。
void* funA(void* arg){
sem_wait(&sem1);
printf("123456789\t");
sem_post(&sem2);
return NULL;
}
(2)在funB内,把原来输出的“2
”改成输出自己的姓名。
void* funB(void* arg){
sem_wait(&sem2);
printf("zhc\n");
sem_post(&sem1);
return NULL;
}
(3)将main函数的for循环次数改为5次。
(4)在main函数的第一个pthread_join
前边,输出“我是主线程,子线程已启动完毕,我将阻塞自己\n”。
(5)在main函数的第二个pthread_join
后边,输出“我是主线程,子线程都已结束,我将继续运行\n”。
for(i=0;i<5;i++){
pthread_create(&tid1,NULL,funA,NULL);
pthread_create(&tid2,NULL,funB,NULL);
printf("我是主线程,子线程已启动完毕,我将阻塞自己\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("我是主线程,子线程都已结束,我将继续运行\n");
}
重新进行编译运行:
六、实验结果
完整代码如下:
#include<semaphore.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
void* funA(void*);
void* funB(void*);
sem_t sem1,sem2;
int main(void){
pthread_t tid1,tid2;
int i=0;
sem_init(&sem1,0,1);
sem_init(&sem2,0,0);
for(i=0;i<5;i++){
pthread_create(&tid1,NULL,funA,NULL);
pthread_create(&tid2,NULL,funB,NULL);
printf("我是主线程,子线程已启动完毕,我将阻塞自己\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("我是主线程,子线程都已结束,我将继续运行\n");
}
printf("\n");
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}
void* funA(void* arg){
sem_wait(&sem1);
printf("123456789\t");
sem_post(&sem2);
return NULL;
}
void* funB(void* arg){
sem_wait(&sem2);
printf("zhc\n");
sem_post(&sem1);
return NULL;
}
运行结果如下:
七、实验总结
这个实验主要是使用 POSIX 线程和信号量来实现线程间的同步输出,让两个线程交替向终端打印字符 “1” 和 “2”。在这个实验中,我学到了如何使用信号量来控制线程的执行顺序,以及如何使用 POSIX 线程库来创建和管理线程。
首先,我对信号量有了更深入的了解。在这个实验中,我使用了两个信号量sem1
和sem2
,分别用于控制两个线程的执行顺序。通过sem_wait
和sem_post
函数来操作信号量,我成功地实现了线程间的同步输出。这让我对信号量的作用有了更清晰的认识,它可以有效地管理和控制线程的执行顺序,避免出现竞争条件和资源冲突。
其次,我对 POSIX 线程库有了更深入的了解。通过使用pthread_create
和pthread_join
函数,我成功地创建了两个线程并等待它们的结束。我意识到线程的创建和管理是需要仔细考虑的,特别是在涉及到线程间的通信和同步时,需要确保线程的执行顺序是可控的和可预测的。
在整个实验过程中,我遇到了一些问题,比如最初的编译错误,但通过查找资料和尝试不同的方法,我最终成功地解决了这些问题。这让我明白了在编程过程中遇到困难时要保持耐心,并且善用搜索引擎和查阅相关文档,这对于解决问题非常重要。
总的来说,这个实验让我对信号量和 POSIX 线程有了更深入的理解,我学会了如何使用它们来实现线程间的同步和协作。同时,我也体会到了在编程实践中遇到问题时要有耐心和勇于尝试新的方法的重要性。这将对我的日后的编程工作和学习都大有裨益。