【DAY25】线程与进程通信:共享内存、同步机制及实现方案

一、线程间通信

1.实现方式

  1. 一个进程空间内部的所有线程共享数据段和堆区,所以全局变量、静态变量、堆区空间都是共享的,可以利用这些空间通信

  2. 多线程操作全局变量空间时会引入资源竞争

  3. 多线程要避免引入资源竞争可以通过加互斥锁解决

  4. 线程间通信最简单的方法:全局变量 + 锁

2.原子操作

不会被CPU任务调度打断的一次最小的操作

3.互斥锁

1.避免多线程资源竞争,配合资源使用,使用资源前加锁,使用资源结束后解锁

2.加锁后,无法再次加锁,必须等到解锁后才能继续加锁

4.临界代码与临界区

  1. 加锁解锁中间的代码称为临界代码或临界区

  2. 临界代码或临界区不可能同时被CPU任务执行

5.互斥锁函数接口

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_destroy(pthread_mutex_t *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

6.死锁

多任务通信过程中由于枷锁导致多个人物均无法向下执行的状态

1.死锁产生的必要条件

互斥条件

不可剥夺条件

请求保持

循环等待

2.解决死锁

1>用pthread_mutex_tylock 替代 pthread_mutex_lock

2>加锁顺序保持一致

7.信号量

同步所有线程,让多个任务执行有先后顺序

1)同步:拥有严格的先后执行的逻辑顺序关系

2)异步:代码执行流程没有任何关联

3)信号量是一个资源,资源可以初始化、销毁、申请、释放

  • 若资源数为0,申请资源时会阻塞等待,等待释放资源后,才能拿到资源
  • 若资源数 >0 ,则申请资源,资源数-1
  • 释放不会阻塞, 资源数+1

8.信号量函数接口

1. sem_init

int set_init (set_t *sem, int pshared, unsigned int value);

功能:

初始化信号量

参数:

  • sem: 信号空间首地址
  • pshared: 信号的作用域

0, 线程间

非0, 进程间

  • valu:信号量的初始值

返回值:

成功返回0; 失败返回非0值

2.sem_destroy

int sem_destroy(sem_t *sem)

功能:

初始化信号量

参数:

  • sem: 信号空间首地址
  • pshared: 信号的作用域

0, 线程间

非0, 进程间

  • valu:信号量的初始值

返回值:

成功返回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

练习:创建3个线程任务,线程任务分别打印A B C

  1. 线程1循环打印A

  2. 线程2循环打印B

  3. 线程3循环打印C

要求三个线程打印出来的顺序总为A B C

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<semaphore.h>

char tmp[4096] = {0};
sem_t w;
sem_t r;
sem_t p;

void* thread1 (void *arg)
{
    while(1)
    {
        sem_wait(&w);
        printf("A");
        sem_post(&p);
    }
    return NULL;
}

void* thread2 (void *arg)
{
    while(1)
    {
        sem_wait(&p);
        printf("B");
        sem_post(&r);
    }

    return NULL;
}

void* thread3 (void *arg)
{
    while(1)
    {
        sem_wait(&r);
        printf("C\n");
        sem_post(&w);
    }

    return NULL;
}
int main(void)
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;

    sem_init(&w, 0, 1);
    sem_init(&r, 0, 0);
    sem_init(&p, 0, 0);

    pthread_create(&tid1, NULL, thread1, NULL);
    pthread_create(&tid2, NULL, thread2, NULL);
    pthread_create(&tid3, NULL, thread3, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);

    sem_destroy(&r);
    sem_destroy(&w);
    sem_destroy(&p);

    return 0;
}

二、进程间通信

1.进程间通信的方式

通过内核通信

1.管道(最简单、最方便)

2.信号

3.消息队列

4.共享内存(最高效)

5.信号灯

6.本地域套接字

2.管道

1.无名管道

  • 只能用于具有亲缘关系的进程间通信

2.有名管道

  • 任意进程间的通信

3.函数接口

1.pipe

int pipe(int pipefd[2]);

功能:

创建一个用于进程间通信的内核缓存区, 返回两个用于读写该内核空间的文件描述符

参数:

pipefd:数组

pipefd[0] : 读文件描述符

pipefd[1] : 写文件描述符

返回值:

成功返回0

失败返回-1

相关推荐
lldhsds2 小时前
kvm虚拟化安装deepin desktop 25 磁盘空间过小弹窗显示为黑屏
linux
川trans2 小时前
云原生--Nginx
linux·运维·服务器·nginx·云原生
txzz88882 小时前
CentOS-Stream-10 Secure Shell服务器sshd_config配置文件
linux·centos·sshd_config·ssh配置
载数而行5202 小时前
算法系列5之交换排序
c语言·数据结构·c++·算法·排序算法
-Try hard-2 小时前
线程间通信 | 避免资源竞争、实现同步通信
linux·开发语言·信息与通信
小虾爬滑丫爬2 小时前
Ubuntu 上设置防火墙
ubuntu·防火墙
Trouvaille ~2 小时前
【项目篇】从零手写高并发服务器(一):项目介绍与开发环境搭建
linux·运维·服务器·网络·c++·高并发·muduo库
!沧海@一粟!2 小时前
Kylin/Linux 服务器健康一键巡检工具
linux·服务器·kylin
’长谷深风‘2 小时前
进程间通信
c语言·进程·进程间通信·软件编程