学校OS操作系统讲解mutex和cond后的实验。
- 实验项目名称
线程同步与互斥
- 实验目的
- 掌握线程的API函数
- 能够区分多线程执行结果产生错误的原因,并能够使用同步和互斥解决问题。
- 实验要求
主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。
要求:
1.子线程输出的线程序号不能重复。
2.全局变量的输出必须递增。
附加要求:
- 按序号次序输出
可以使用两种方法,第一种只用mutex互斥锁(那这节课讲的cond条件变量就没什么用了doge),第二种是使用mutex和cond。
法一:mutex
每次create完再join等待线程结束。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int count;
void* mythread(void * arg){
sleep(2); //sleep(50)
pthread_mutex_lock(&lock);
count++;
pthread_mutex_unlock(&lock);
sleep(0);
printf("线程 %d count : %d\n", (int) arg, count);
return NULL;
}
int main(){
pthread_mutex_init(&lock, NULL);
pthread_t p[10];
int i = 0;
for(; i < 10; i ++){
pthread_create(&p[i], NULL, mythread, (void*) i);
pthread_join(p[i], NULL);
}
pthread_mutex_destroy(&lock);
return 0;
}
CentOS运行结果:
法二:mutex + cond
因为create调用线程后,各个线程的执行顺序是随机的,要使后面按照线程序号唤醒各个线程,就要依次将各个线程放入wait休眠队列,这样在signal唤醒线程时才能依次发出信号。
使用了tiket将线程依次进行休眠。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int count;
int tiket = 1;
void* mythread(void * arg){
int tmp = (int) arg;
printf("enter pthread:%d \n", tmp);
while(!tmp) //特判第一个线程(线程0)
if(tiket == tmp) break; //后序线程全部按序进行wait休眠队列后,break
while(tiket != tmp){
//很愚蠢的自旋,为了让各个线程按照次序进行休眠
}
pthread_mutex_lock(&lock);
if(tmp){ //非第一个线程
tiket = (tiket + 1) % 10;
printf(" pthread %d ready to wait\n", tmp);
pthread_cond_wait(&cond, &lock); //进入休眠队列
}
//开始进行对全局变量的++操作。
sleep(2); //sleep(50)
count++;
tiket++;
printf("pthread %d count : %d\n", tmp, count);
printf(" ready to call pthread %d\n", tiket);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
sleep(0);
return NULL;
}
int main(){
pthread_mutex_init(&lock, NULL);
pthread_t p[10];
int i = 0;
for(; i < 10; i ++){
pthread_create(&p[i], NULL, mythread, (void*) i); //传入线程序号i
}
for(i = 0; i < 10; i ++){
pthread_join(p[i], NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
CentOS运行结果:
可以看出,每次create后,各个线程的运行是随机的,并不会按照create的调用顺序来运行线程。