实验目的
- 系统调用的进一步理解。
- 进程上下文切换。
- 同步的方法。
实验题目
1. 通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确
分析:
首先使用fork产生P1进程,之后产生P2、P3进程,此时需要在P2和P3之间加互斥锁,P2和P3互斥访问临界资源并执行,随后当P2或P3至少一个进程完成时,执行fork产生P4进程。
互斥变量使用数据类型:pthread_mutex_t
,使用互斥量前要先初始化,使用的函数如下:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
然后使用pthread_mutex_lock(&mutex) 和 pthread_mutex_unlock(&mutex) 分别为进程上锁和解锁,从而实现互斥操作。
程序代码编写如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pid_t pid1 = fork();
if(pid1 == 0){
printf("I'm the process P1.\n");
return 0;
}
waitpid(pid1, NULL, 0);
pid_t pid2 = fork();
if(pid2 == 0){
pthread_mutex_lock(&mutex);
printf("I'm the process P2.\n");
pthread_mutex_unlock(&mutex);
return 0;
}
waitpid(pid1, NULL, 0);
pid_t pid3 = fork();
if(pid3 == 0){
pthread_mutex_lock(&mutex);
printf("I'm the process P3.\n");
pthread_mutex_unlock(&mutex);
return 0;
}
int pr2 = waitpid(pid2, NULL, 0);
int pr3 = waitpid(pid3, NULL, 0);
pid_t pid4 = fork();
if(pid4 == 0 && (pr2 == pid2 || pr3 == pid3)){ /*P2和P3有一个完成即可进行P4*/
printf("I'm the process P4.\n");
return 0;
}
else if(pid1 != -1){
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
waitpid(pid3, NULL, 0);
waitpid(pid4, NULL, 0);
}
pthread_mutex_destroy(&mutex);
return 0;
}
编译执行,程序运行结果如下图所示,执行顺序为P1、P2、P3、P4
为了看出P2和P3互斥运行的关系,之后在P2线程内加入睡眠1s
if(pid3 == 0){
sleep(1); //新加
pthread_mutex_lock(&mutex);
printf("I'm the process P3.\n");
pthread_mutex_unlock(&mutex);
return 0;
}
运行结果如下,执行顺序变为P1、P2、P3、P4
可以发现P2和P3的顺序是不确定的,某一个运行之后才会运行另一个。
2. 火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。
分析:同步机制就是设置两个信号量,分别是product和consume, 分别用来表示buf缓存区中空闲单元的个数和buf缓存区中非空闲单元的个数,并初始化consume信号量个数为1000。每次售票前都检测非空闲单元数是否大于0,成功售出一张票之后将product信号量增一,同时将ticketCount减一;退票前检测空闲单元数是否大于0,成功退票后consume信号量增一,同时ticketCount加一。
不含同步机制的代码编写如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
int ticketCount = 1000;
int temp;
void *sale(void *arg) {
for (int i = 0; i < 1050; i++){
temp = ticketCount;
pthread_yield();
temp = temp - 1;
pthread_yield();
ticketCount = temp;
printf("sale: %d ticketCount: %d ",i, ticketCount);
}
return NULL;
}
void *refund(void *arg) {
for (int i = 0; i < 1050; i++){
temp = ticketCount;
pthread_yield();
temp = temp + 1;
pthrea