85-线程同步

来源:互联网 发布:大数据开发需要学什么 编辑:程序博客网 时间:2024/06/05 11:33

本文通过一个具体案例来说明什么是线程同步。

1. 问题提出

学生线程写作业,老师线程检查作业。要求:只有学生线程写完作业了,老师线程才能检查作业。

在此问题中,有两个线程:学生线程和老师线程,和以往的线程互斥不一样的是,线程互斥之间没有明确的的执行顺序上的要求。而线程同步,有了顺序上的要求,即有先后关系:只有学生线程完成了作业以后,老师线程才能够去运行!

2. 解决思路

在我们没有学习线程同步的方法前,除了采用信号量机制和轮询,好像还没有更好的方法来解决此问题。如果不允许使用信号量的话,用轮询该怎么做?轮询是指:老师线程可以不断的去询问学生作业到底有没有完成作业。

具体做法是采用全局变量 finished 做标记,初始化为 0,表示学生还未完成作业。学生如果完成了作业,会将 finished 变量设置为 1.

另一方面,老师线程不断的检查 finished 变量是否为 1 来判断学生完成了作业。

下面是伪代码:

void student() {  // doing homework  sleep(5);  lock(mutex);  finished = 1;  unlock(mutex);}void teacher() {  // 不断检查标记是否为 1  lock(mutex);  while(finished == 0) {    unlock(mutex);    sleep(1);    lock(mutex);  }  unlock(mutex);  // 执行到这里说明学生已经完成了作业}

很显然,全局变量 finished 属于共享资源,需要使用互斥手段对其进行互斥访问,否则容易出现错误。

说明:在此例中不需要给 finished 变量加互斥锁也不会错,因为老师线程只做了读操作。但是,为了防止产生竞争错误,其次为了后续讨论方便,这里索性加上互斥锁。

3. 程序清单

3.1 代码

#include <stdio.h>#include <pthread.h>int finished = 0;pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void* do_homework(void* arg) {  // doing homework  sleep(5);  // finished  pthread_mutex_lock(&lock);  finished = 1;  pthread_mutex_unlock(&lock);}void* check_homework(void* arg) {  // 打电话  sleep(1);  // 电话接通  pthread_mutex_lock(&lock);  // 作业写完了吗?  printf("老师:作业写完了吗?!\n");  while(finished == 0) {    // 没写完呐!    printf("学生:没写完呐!\n");    pthread_mutex_unlock(&lock);    // 好的,你接着写    printf("老师:好的,你接着写吧!\n");    printf("-------------------------\n");    sleep(1);    pthread_mutex_lock(&lock);    printf("老师:作业写完了吗?!\n");  }  printf("学生:写完啦!\n");  pthread_mutex_unlock(&lock);  printf("老师开始检查---------------\n");}int main() {  pthread_t tid1, tid2;  pthread_create(&tid1, NULL, do_homework, NULL);  pthread_create(&tid2, NULL, check_homework, NULL);  pthread_join(tid1, NULL);  pthread_join(tid2, NULL);  return 0;}

3.2 编译和运行

  • 编译和运行
$ gcc do_homework.c -o do_homework -lpthread$ ./do_homework
  • 运行结果


这里写图片描述
图1 运行结果

3.3 结果分析

从图 1 中可以看到,老师一直问了学生 5 次,其中 4 次询问得到的答复都是没写完……

虽然本程序的结果正确,但是大家也可以看到,老师反复的询问学生,效率低下。如果学生做作业十分的慢,也不知道要做多久,老师就会一直问下去,这无疑是对老师宝贵时间的浪费(也就是浪费 cpu 资源)。

如果有一种方法,可以让学生在完成后作业后唤醒老师线程,不就好了吗?这就是所谓的好莱坞式编程:Do not call me! I will call you (别打我电话,我会通知你的).

在下一节里就会介绍这种技术——条件变量。

4. 总结

  • 理解何为线程同步
  • 知道在没有信号量和条件变量的时候,如何使用互斥来完成线程同步

练习:理解轮询机制是如何工作的,同时完成本文中的实验。

0 0