先来看看线程同步的概念,线程同步是指同一个进程中的所有线程都是并发执行的,当线程需要访问临界区资源时,必须按照一定的先后顺序访问执行。
控制线程同步的方式有线程级信号量、互斥锁(读写锁、自旋锁)、条件变量。
线程级信号量
可能有人会疑惑,为什么这里要说线程级的信号量?这是因为,在Linux操作系统上,存在两组信号量API,一组是System V IPC信号量,也叫进程级的信号量,另一组是POSIX信号量,是我们这里的线程级信号量。这里讲一下信号量的概念,信号量是一种特殊的变量,取值为自然数,只支持两种操作:P操作和V操作。之前也已经介绍过P、V操作是做什么的,这里就不再重述了。
线程级信号量通过5个函数来实现对线程同步的控制:
#include <semaphore.h>
int sem_init(sem_t *sem,int pshared,int value) //用于初始化一个未命名的信号量
int sem_destroy(sem_t *sem); //用于销毁信号量
int sem_wait(sem_t *sem); //P操作,信号量减1
int sem_trywait(sem_t *sem); //sem_wait()函数的非阻塞版本
int sem_post(sem_t *sem) //V操作,信号量加1
上面这些函数中第一个参数sem都指向被操作的信号量,sem_init函数中pshared参数指定信号量的类型,若pshared值为0表示信号量为当前进程的局部信号量,否则该信号量可以在多个进程间共享。value参数指定信号量的初始值。
所有函数函数成功时返回0,失败时返回返回-1,并设置errno。
此外系统禁止初始化已经初始化过的信号量。
互斥锁
互斥锁,也称互斥量,可以用于保护关键代码段,以确保其单独式的访问,类似于二进制的信号量。当访问该代码段时,需要获得互斥锁,并对其进行加锁,这一点等同于二进制信号量的P操作;访问完该代码段后,需要对其进行解锁,以唤醒其他等待该互斥锁的线程,这也等同于于二进制信号量的V操作。
互斥锁提供5个相关函数来实现线程同步
#include<pthread.h>
//用于初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);
//用于销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//以原子操作的形式对一个互斥锁加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//相当于pthread_mutex_lock函数的非阻塞版本
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//以原子操作的形式对一个互斥锁解锁
int pthread_mutex_unlock(pthread _mutex_t *mutex);
这些函数第一个参数mutex指向目标互斥锁,互斥锁的类型是pthread_mutex_t结构体。pthread_mutex_init函数参数mutexattr指定互斥锁的属性,如果将其设置为NULL,则表示使用默认属性。所有函数成功时返回0,失败时返回错误码。
条件变量
相比于互斥锁是用于对线程同步对共享数据的访问,条件变量则是用于线程之间同步共享数据的值。条件变量实现了线程间的一种通知机制,即当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。
条件变量的相关函数有5个:
#include <pthread.h>
//用于初始化条件变量
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr *cond_attr);
//用于销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
//以广播的方式唤醒所有等待目标条件变量的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
//用于唤醒一个等待目标条件变量的线程
int pthread_cond_signal(pthread_cond_t *cond);
//用于等待目标条件变量
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
这些函数第一个参数cond指向要操作的目标条件变量,条件变量的类型是pthread_cond_t结构体。pthread_cond_init函数的cond_attr参数指定条件变量的属性,如果将其设置为NULL,表示使用默认属性。pthread_cond_wait函数的的mutex参数是用于保护条件变量的互斥锁,以确保其操作的原子性。在调用pthread_cond_wait函数之前必须保证互斥锁mutex已加锁,否则会出错。
所有函数成功时返回0,失败时返回错误码。
文章主要介绍线程级信号量、互斥锁、条件变量这三个内容、至于文中提到的读写锁、自旋锁感兴趣的小伙伴可以去查阅相关资料,这里我们不展开介绍,以上。