一、实现方式
1.一个进程空间内部的所有线程共享数据段和堆区,所以全局变量、静态变量,堆区空间都是共享的,可利用这些空间通信;
2.多线程操作全局变量空间时会引入资源竞争;
3.多线程可通过加互斥锁避免资源竞争问题;
4.线程间通信最简单的方法:全局变量+锁
二、原子操作
不会被CPU任务调度打断的一次最小的操作
三、互斥锁
避免多线程资源竞争,配合资源使用,使用资源前加锁,使用资源结束后解锁;
加锁后,无法再次加锁,必须等到解锁后才能继续加锁。
加锁不能阻止CPU任务调度,只是避免资源竞争问题 ,后一个线程想要执行,需等到前一个线程解锁之后才有可能执行。
四、临界代码与临界区
加锁解锁中间的代码称为临界代码或临界区;
临界代码和临界区不可能同时被CPU执行。
五、互斥锁函数接口
1.pthread_mutex_init
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能:互斥锁初始化(在线程创建前初始化)
参数:
mutex:互斥锁空间首地址;
attr:互斥锁属性默认传NULL
返回值:
成功返回0;
失败返回非0
2.pthread_mutex_destory
int pthread_mutex_destory(pthread_mutex_t *restrict mutex);
功能:互斥锁销毁(在线程结束后销毁)
参数:
mutex:互斥锁空间首地址;
返回值:
成功返回0;
失败返回非0
3.pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:互斥锁加锁
参数:
mutex:互斥锁空间首地址;
返回值:
成功返回0;
失败返回非0
4.pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:互斥锁解锁
参数:
mutex:互斥锁空间首地址;
返回值:
成功返回0;
失败返回非0
六、死锁
多任务通信过程中由于加锁导致多个任务均无法向下执行的状态
1.死锁产生的四个必要条件
- 互斥条件
- 不可剥夺条件
- 请求保持
- 循环等待
2.解决死锁
- 用pthread_mutex_trylock替代pthread_mutex_lock,如果无法加锁成功完成异常处理流程,防止程序卡死
- 加锁顺序保持一致

示例:
cpp
#include<stdio.h>
#include<pthread.h>
int Num = 100;
int TmpValue1 = 0;
int TmpValue2 = 0;
pthread_mutex_t lock;
void *ThreadFun1(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock);
TmpValue1 = Num;
TmpValue2 = Num;
Num++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
void *ThreadFun2(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock);
if(TmpValue1 != TmpValue2)
{
printf("TmpValue1 = %d TmpValue2 = %d\n", TmpValue1, TmpValue2);
}
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(void)
{
pthread_t tid1;
pthread_t tid2;
pthread_mutex_init(&lock, NULL);
pthread_create(&tid1, NULL, ThreadFun1, NULL);
pthread_create(&tid2, NULL, ThreadFun2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&lock);
return 0;
}
七、信号量
1.信号量可实现多线程间的同步,让多个任务具有先后顺序关系
同步:具有严格的先后执行的逻辑关系;
异步:代码执行流程没有任何关联性。
2.信号量是一个资源,资源可以初始化、销毁、申请和释放
如果资源数>0,则申请资源是让资源数-1;
如果资源数为0,申请资源时则会阻塞等待,等待有人释放资源,释放资源不会阻塞,会让资源数+1.
八、信息量的函数接口
1.sem_init
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:对信号量初始化;
参数:
sem:信号量空间首地址;
pshared:信号量作用域;
value:信号量的初始值
返回值:
成功返回0;
失败返回非0
2.sem_destory
int sem_destory(sem_t *sem);
功能:销毁信号量;
参数:
sem:信号量空间首地址;
返回值:
成功返回0;
失败返回非0
3.sem_wait
int sem_wait(sem_t *sem);
功能:申请资源,让资源数-1,如果资源数为0,则阻塞等待
参数:
sem:信号量空间首地址;
返回值:
成功返回0;
失败返回非0
4.sem_post
int sem_post(sem_t *sem);
功能:释放资源,让资源数+1
参数:
sem:信号量空间首地址;
返回值:
成功返回0;
失败返回非0
示例:创建三个线程,线程1循环打印A,线程2循环打印B,线程3循环打印C,按顺序打印出ABC
cpp
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
sem_t sem1_w;
sem_t sem2_w;
sem_t sem3_w;
void *ThreadFun1(void *arg)
{
while(1)
{
sem_wait(&sem1_w);
printf("A");
sem_post(&sem2_w);
}
return NULL;
}
void *ThreadFun2(void *arg)
{
while(1)
{
sem_wait(&sem2_w);
printf("B");
sem_post(&sem3_w);
}
return NULL;
}
void *ThreadFun3(void *arg)
{
while(1)
{
sem_wait(&sem3_w);
printf("C\n");
sem_post(&sem1_w);
}
return NULL;
}
int main(void)
{
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
sem_init(&sem1_w, 0, 1);
sem_init(&sem2_w, 0, 0);
sem_init(&sem3_w, 0, 0);
pthread_create(&tid1, NULL, ThreadFun1, NULL);
pthread_create(&tid2, NULL, ThreadFun2, NULL);
pthread_create(&tid3, NULL, ThreadFun3, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
sem_destroy(&sem1_w);
sem_destroy(&sem2_w);
sem_destroy(&sem3_w);
return 0;
}