临界区

临界区

2019519

18:46

   

多个线程在同时调用函数时可能会产生问题,可能会产生问题的这部分代码称之为临界区(Critical Section)。

根据临界区是否会产生问题,函数可分为:

  • 线程安全函数(Threa-safe function)
  • 非线程安全函数(Thread-unsafe function)

   

线程安全函数被多个线程同时调用也没有问题,但是非线程安全函数就可能会引发问题。

大多数标准函数都是线程安全函数,我们不需要自己区分线程安全函数与非线程安全函数。因为他们大都数时候都提供了非线程安全函数的对应线程安全版本。

在涉及线程的代码中,我们可以同在在头文件声明前定义_REENTRANT宏来说明调用线程安全函数

也可以通过在编译时添加-D_REENTRANT选项定义宏

   

$ gcc -D_REENTRANT mythread.c -o mythread -lpthread

   

线程存在的问题和临界区

任何内存空间只要是被线程同时访问,就有可能发生问题。

为了解决这个临界区的问题其实很简单,就是不让不同线程同时访问一个变量。而实现这个就是 线程同步

线程同步可以解决两方面的情况:

  • 不能同时访问同一内存空间
  • 需要指定访问同一内存空间的线程执行顺序

   

互斥量 Mutual Exclusion

表示不允许多个线程同时访问,互斥量主要用于结局线程同步的问题。

我们通过互斥量实现互斥锁,在一个线程在访问变量时就将他锁住,而等到访问完毕再释放这把锁。

   

创建与删除互斥量

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex,

const pthread_mutexattr_t *attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

->>成功时返回0,失败时返回其他值

   

mutex: 互斥量指针

attr:创建互斥量需要指定的属性,默认值则传递NULL

   

上锁与解锁

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

   

当其他线程调用pthread_mutex_lock函数预备进入临界区时,如果发现有其他线程已经进入临界区。将使这个函数阻塞,一直到那个线程调用pthread_mutex_unlock解锁

   

pthread_mutex_lock(&mutex);

// 临界区开始

// ….

//临界区结束

pthread_mutex_unlock(&mutex);

   

如果线程退出临界区使,而没有调用pthread_mutex_unlock函数,那么其他线程的pthread_mutex_lock函数将一直处于阻塞状态。这种情况称之为死锁。

   

互斥量lock,unlock函数的频繁调用使程序的执行效率降低。所以应该对于不同的程序适当的考虑是应该扩大还是缩小临界区。

   

信号量 Semaphore

顾名思义。与互斥量的开锁与解锁相比。信号量就是给一个信号,看是否复合条件能通过。

   

信号量的创建和销毁

#include <semaphore.h>

int sum_init(sem_t *sem, int pshared, unsigned int value);

int sem_destroy(sem_t *sem);

->>成功时返回0,失败时返回其他值

   

sem: 保存信号量的地址

pshared: 传递其他值是,创建可有多个进程共享的信号量。传递0时,只允许一个进程内部使用。

value:信号量的初始值

   

相当于互斥量的开锁与解锁的函数

#include <semaphore.h>

int sem_post(sem_t *sem);

int sem_wait(sem_t *sem);

->>成功时返回0,失败时返回其他值

   

sem:保存信号量的地址

传递给sem_post函数时增加1

传递给sem_wait函数时减少1,当信号量值必须大于等于0

   

也就是通过调用sem_wait函数时检查信号量的值是否满足要求才继续下去,否则就阻塞。等到其他线程调用sem_post使这个信号量满足要求。

调用sem_wait函数进入临界区的线程再调用sem_post函数前不允许其他线程进入临界区。信号量的值在0和1之间跳转。具有这种特性的机制被称为"二进制信号量"。