多线程操作与安全
1 互斥锁
1.1 使用场景
互斥锁的特性:
当遇到锁被占用,会进行cpu切换,等锁可以用后再切换回来。
使用场景:
操作复杂耗时或者存在有系统调用,采用互斥锁。
1.2 基本操作
锁的使用很简单,就三个api,初始化,加锁,解锁。需要注意锁的粒度,一般是需要根据临界资源大小来定。有时候也会因为降低代码复杂度,增加锁的粒度。
#include <pthread.h>
pthread_mutex_t mutex;
//1. 初始化
pthread_mutex_init(&mutex, NULL);
//2. 加锁
pthread_mutex_lock(&mutex);
//3. 解锁
pthread_mutex_unlock(&mutex);
//4. 释放
pthread_mutex_destroy(&mutex);
2 自旋锁
2.1 使用场景
自旋锁的特性:
当遇到锁被占用,不会让出cpu,空转等待。
使用场景:
临界资源操作简单时间短,没有系统调用,采用自旋锁。
2.2 基本操作
初始化带一个选项参数,一般采用PTHREAD_PROCESS_SHARED,允许多线程操作自旋锁。其他操作与互斥锁一致,就是使用场景上的差别。
#include <pthread.h>
pthread_spinlock_t spinlock;
//1. 初始化
//PTHREAD_PROCESS_SHARED:允许任何有权访问分配自旋锁的内存的线程操作自旋锁
pthread_spin_init(&spinlock, PTHREAD_PROCESS_SHARED);
//2. 加锁
pthread_spin_lock(&spinlock);
//3. 解锁
pthread_spin_unlock(&spinlock);
//4. 释放
pthread_spin_destroy(&spinlock);
3 原子操作
3.1 使用场景
原子操作的特性:
原子操作是也是解决线程安全的一种操作,将复杂的操作变成一条cpu指令。
使用场景:
原子操作主要是指令集的操作,需要cpu的指令集支持才
3.2 基本操作
这里实现两个比较常用的原子操作一个是自增或者自减运算,利用的是汇编指令支持;另一个是比较火的指令CAS(compare and swap)操作,它也是需要cpu指令集支持,具体功能是比较并且替换。
//自增原子操作
int inc(int *value, int add) {
int old;
__asm__ volatile (
"lock; xaddl %2, %1;"
: "=a" (old)
: "m" (*value), "a" (add)
: "cc", "memory"
);
return old;
}
//CAS原子操作(比较a==b,a=c)
cmpxchg(a, b, c);
//相当于
if(a == b)
{
a = c;
}
4 线程私有空间
4.1 使用场景
线程私有空间的特性:
预先为线程开辟私有空间,线程内部共享。
使用场景:
线程私有空间为了解决线程内部的资源的共享,类似线程内部的全局变量。
4.2 基本操作
私有空间操作也比较简单,创建私有空间;设置私有空间值,支持结构体,字符串,数字等等;获取私有空间数据主要是利用get函数和强转即可。支持跨函数传递,只要在线程内即可。
#include <pthread.h>
pthread_key_t key;
//1. 私有空间创建
pthread_key_create(&key, NULL);
//2. 设置数据到私有空间
pthread_setspecific(key, ptr);
//3. 获取数据
ptr = pthread_getspecific(key);
//4. 释放
pthread_key_delete(key);
5 信号量
5.1 使用场景
信号量的特性:
阻塞等待条件触发后才执行;
使用场景:
一般用于生产消费模型,生产者负责发送通知,消费者当生产队列为空则阻塞等待。
5.2 基本操作
信号量操作,包括初始化;信号通知;信号等待;广播通知和释放操作;需要注意的是等待信号需要与锁配合使用。broadcast是唤醒所有被阻塞的线程,一般在cond释放的时候使用。
#include <pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
//1. 初始化
pthread_cond_init(&cond);
//3. 等待需要与互斥锁配合使用
pthread_mutex_lock(&pool->mtx);
while (pool->cons == NULL) {
if (pool->terminate) break;
pthread_cond_wait(&pool->cond, &pool->mtx);
}
pthread_mutex_unlock(&pool->mtx);
//3. 单一通知信号
pthread_cond_signal(&cond);
//4. 广播通知信号
pthread_cond_broadcast(&cond);
//5. 释放
pthread_cond_destroy(&cond);