85-线程同步

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

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. 总结

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

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

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值