当前位置: 首页 > news >正文

Linux学习-(进程间,线程间通信)

异步:多线程、多进程本质是异步执行

线程间同步机制:让多个线程在执行某个任务时,具有先后顺序的执行

信号量


实现线程间同步。

步骤:1. 定义信号量对象:sem_t
2. 初始化信号量:sem_init();
3. 申请信号量:P操作:int sem_wait(sem_t *sem);
释放信号量:V操作:int sem_post(sem_t *sem);
PV操作
4. 销毁信号量:int sem_destroy(sem_t *sem);

主要函数

int sem_init(sem_t *sem, int pshared, unsigned int value);

功能

初始化信号量

参数

sem:要初始化的信号量对象地址
pshared:
0:线程间共享
非0:进程间共享
value:信号量的初始值(初始资源数)

返回值

成功:0
失败:-1

练习

创建三个线程,分别按顺序打印A-> B -> C

#include<stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include<unistd.h>
sem_t sem_a;
sem_t sem_b;
sem_t sem_c;void*task1(void*arg)
{while(1){sem_wait(&sem_a);printf("A\n");sem_post(&sem_b);sleep(1);}}void*task2(void*arg)
{while(1){sem_wait(&sem_b);printf("B\n");sem_post(&sem_c);sleep(1);}
}void*task3(void*arg)
{while(1){sem_wait(&sem_c);printf("C\n");sem_post(&sem_a);sleep(1);}
}int main(int argc,const char*argv[])
{pthread_t tid[3];sem_init(&sem_a,0,1);sem_init(&sem_b,0,0);sem_init(&sem_c,0,0);pthread_create(&tid[0],NULL,task1,NULL);pthread_create(&tid[1],NULL,task2,NULL);pthread_create(&tid[2],NULL,task3,NULL);pthread_join(tid[0],NULL);pthread_join(tid[1],NULL);pthread_join(tid[2],NULL);sem_destroy(&sem_a);sem_destroy(&sem_b);sem_destroy(&sem_c);return 0;}

死锁

死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,
且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。

现象

现象1:忘记释放锁
现象2:重复加锁
现象3:多线程多锁,抢占锁资源不当
如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁

产生死锁的四个必要条件

(1)互斥条件:一个资源每次只能被一个进程使用(一个执行流获取锁后,其它执行流不能再获取该锁)。
(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放(执行流本身使用着一把锁并不释放,还在请求别的锁)。
(3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺(A执行流拿着锁,其它执行流不能释放)。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)。

解决方法

1.锁一定要成对出现
2.使线程的加锁顺序一致
3.破坏环路等待条件
使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的锁
pthread_mutex_trylock();
int sem_trywait(sem_t *sem);

进程间通信

IPC机制(interprocess communicate)

进程间空间独立,无法直接通信,需要IPC机制实现通信。

同一主机进程间通信

1、古老的通信方式
无名管道
有名管道
信号:进程间通知机制
2、IPC对象通信system v
共享内存*:效率最高
消息队列
信号量集(信号灯)

主要用在不同主机进程间通信

3、socket通信
网络通信

IPC机制

有名管道:可以用于同一主机,任意进程间通信
无名管道:只能用于同一主机,具有亲缘关系的进程间通信(父子进程间)

无名管道

操作流程

1. 创建无名管道:pipe();  pipefd[0] ---->读端
2. 写管道-->write();     pipefd[1] ---->写端
3. 读管道-->read();
4. 关闭管道-->close();

管道本质

内核空间中的一段缓冲区,遵循先进先出特点。
无名管道的:读端:pipefd[0]
写端:pipefd[1]
读写端不能交换。
无名管道默认大小:65536bytes = 64K

管道特性

1. 写阻塞:读端和写端都存在,向管道中写数据,当管道满时,发生写阻塞。
2. 读阻塞:读端和写端都存在,从管道中读数据,若管道为空,则发生读阻塞。
3. 读返回0:当写端关闭,从管道中读数据,若管道中有数据,则读到数据;
若管道中没有数据,read则返回0,不再阻塞。
4. 管道破裂:读端关闭,向管道中写入数据,发生管道破裂(异常)

练习

父进程从终端获取数据,子进程负责打印

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc,const char*argv[])
{int pipefd[2];int ret = pipe(pipefd);if (ret < 0){perror("pipe error");return -1;}char buff[1024] = {0};fgets(buff,sizeof(buff),stdin);pid_t pid = fork();if(pid > 0){close(pipefd[0]);write(pipefd[1],buff,strlen(buff));close(pipefd[1]);wait(NULL);}else if(0 == pid){close(pipefd[1]);read(pipefd[0], buff, sizeof(buff));printf("buff = %s\n", buff);close(pipefd[0]);}else{perror("fork error");}return 0;
}

有名管道

操作流程

1. 创建管道文件 mkfifo、mkfifo();
2. 打开管道文件 open();
3. 写管道文件 write();
4. 读管道文件 read();
5. 关闭管道文件 close();
6. 删除管道文件 int remove(const char *pathname);

管道本质

内核空间的一段缓冲区,但这块缓冲区和一个管道文件相关联。

主要函数

int mkfifo(const char *pathname, mode_t mode);
功能:创建一个管道文件
参数:
pathname:管道文件的名称
mode:管道文件的读写执行权限
返回值:
成功:0;
失败:-1

练习

一个进程负责从终端获取数据,通过有名管道,使另一个进程打印数据

文件1:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main(int argc,const char*argv[])
{int ret = mkfifo("./mkfifo",0664);if(ret != 0 && errno != EEXIST){perror("mkfifo error");return -1;}int fd1 = open("./1.txt",O_RDONLY);int fd2 = open("./mkfifo",O_WRONLY);if(fd1 < 0 || fd2 < 0){perror("open error");return -1;}char buff[1024] = {0};ssize_t cnt = read(fd1,buff,sizeof(buff));while(cnt != 0){write(fd2,buff,cnt);cnt = read(fd1,buff,sizeof(buff));}close(fd1);close(fd2);remove("./mkfifo");return 0;}
文件2:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main(int argc,const char*argv[])
{int ret = mkfifo("./mkfifo",0664);if(ret != 0 && errno != EEXIST){perror("mkfifo error");return -1;}int fd1 = open("./mkfifo",O_RDONLY);int fd2 = open("./2.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);if(fd1 < 0 || fd2 < 0){perror("open error");return -1;}char buff[1024] = {0};ssize_t cnt = read(fd1,buff,sizeof(buff));while(cnt != 0){write(fd2,buff,cnt);cnt = read(fd1,buff,sizeof(buff));}close(fd1);close(fd2);return 0;}







http://www.dtcms.com/a/336926.html

相关文章:

  • nuScence数据集
  • 计算机视觉 图像处理 在两张二值图中检测线条交集点的高效方法 适合工程图纸比对、生物神经元网络分析和文档特征提取等场景 ,
  • 20. 云计算-Service MeshServerless
  • 谷粒商城项目-P3简介-分布式基础概念
  • CloudBase AI ToolKit + VSCode Copilot:打造高效智能云端开发新体验
  • 【运维进阶】LNMP + WordPress 自动化部署实验
  • CMakeLists.txt 学习笔记
  • MariaDB/MySQL 客户端工具与服务端配置精要指南
  • C++---有符号和无符号整数的位移操作
  • 云原生俱乐部-mysql知识点归纳(1)
  • 《亚矩阵云手机重构出租接单:KVM 虚拟化与边缘计算驱动的设备替代技术路径》
  • 8.18决策树
  • 性能测试(Jemter)
  • grep命令要点、详解和示例
  • 基于nvm安装管理多个node.js版本切换使用(附上详细安装使用图文教程+nvm命令大全)
  • QT第九讲- 控件委托
  • Git智能合并机制深度解析
  • ChatGPT-5 对教育行业的影响与案例研究
  • Qt笔试题
  • 录像视频删除如何恢复?手机电脑的录像恢复技巧
  • 给linux的root磁盘扩容
  • 手游搬砖对云手机的需求有哪些?
  • 机器学习实例应用
  • 获粤港澳大湾区碳足迹认证:遨游智能三防手机赋能绿色通信
  • VLN视觉语言导航(3)——神经网络的构建和优化 2.3
  • 二十八、案例-部门管理-查询
  • Android中flavor的使用
  • 项目实战——矿物识别系统(利用机器学习从化学元素数据中识别矿物,从数据到分类模型)
  • 咨询进阶——解读咨询顾问技能模型
  • NL2SQL 技术深度解析与项目实践