线程间通信 | 避免资源竞争、实现同步通信

一、实现方式

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;
}
相关推荐
cici158741 小时前
基于C#的智能仓储上位机系统实现方案
开发语言·c#
楼田莉子1 小时前
C++并发库介绍(上)
开发语言·c++·学习
Nightmare0041 小时前
切换conda环境的时候输出zstandard could not be imported. Running without .conda support.
开发语言·python·conda
Trouvaille ~1 小时前
【项目篇】从零手写高并发服务器(一):项目介绍与开发环境搭建
linux·运维·服务器·网络·c++·高并发·muduo库
weixin_395448911 小时前
build_fsd_luyan_from_rm——注释
开发语言·windows·python
!沧海@一粟!1 小时前
Kylin/Linux 服务器健康一键巡检工具
linux·服务器·kylin
岳清源1 小时前
【无标题】haproxy七层管理
linux
lsx2024061 小时前
NumPy 算术函数
开发语言
程序员南飞1 小时前
算法笔试-求一个字符串的所有子串
java·开发语言·数据结构·python·算法·排序算法