嵌入式(day30)进程间通信 IPC(有名、无名管道)
一、异步:多线程、多进程本质是异步执行
线程间同步机制:让多个线程在执行某个任务时,具有先后顺序的执行。
信号量:实现线程间同步。
操作步骤:
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);

5、int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量
参数:
sem:要初始化的信号量对象地址
pshared:
0:线程间共享
非0:进程间共享
value:信号量的初始值(初始资源数)
返回值:
成功:0
失败:-1
6、

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem_A;
sem_t sem_B;
sem_t sem_C;
//set_t sem w;
//set_t sem r;
void *task1(void *arg)
{
while(1)
{
sem_wait(&sem_A);
//fgets(buff,sizeof(buff),stdin);
printf("A\n");
sem_post(&sem_B);
}
}
void *task2(void *arg)
{
while(1)
{
sem_wait(&sem_B);
printf("B\n");
sem_post(&sem_C);
}
}
void *task3(void *arg)
{
while(1)
{
sem_wait(&sem_C);
printf("C\n");
sem_post(&sem_A);
}
}
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、死锁:死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,
且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。
现象:
现象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);
三、多任务并发
1. 多进程
2. 多线程
3. 进程间通信:IPC机制(interprocess communicate)
原因:进程间空间独立,无法直接通信,需要IPC机制实现通信。
同一主机进程间通信
1、古老的通信方式
无名管道
有名管道
信号:进程间通知机制
2、IPC对象通信 system v
共享内存*:效率最高
消息队列
信号量集(信号灯)
主要用在不同主机进程间通信
3、socket通信
网络通信
IPC机制:
1. 管道
有名管道:可以用于同一主机,任意进程间通信
无名管道:只能用于同一主机,具有亲缘关系的进程间通信(父子进程间)


#include <stdio.h>
#include <unistd.h>
int main(int argc,const char *argv[])
{
int pipfd[2];
int ret = pipe(pipfd);
if(ret < 0)
{
perror("pipe error");
return -1;
}
pid_t pid = fork();
if(pid>0)
{
char buff[1024] = 0;
close(pipfd[0]);
fgets(buff,sizeof(buff),stdin);
write(pipefd[1], buff, strlen(buff));
close(pipfd[1]);
wait(NULL);
}
else if(pid == 0)
{
close(pipfd[1]);
char buff[1024] = {0};
read(pipfd[0],buff,sizeof(buff));
printf("buff = %s\n",buff);
close(pipfd[0]);
}
else
{
perror("fork error");
}
}
2、管道本质:
内核空间中的一段缓冲区,遵循先进先出特点。
无名管道的:读端:pipefd[0]
写端:pipefd[1]
读写端不能交换。
无名管道默认大小:65536bytes = 64K
3、管道的特性:
1. 写阻塞:读端和写端都存在,向管道中写数据,当管道满时,发生写阻塞。
2. 读阻塞:读端和写端都存在,从管道中读数据,若管道为空,则发生读阻塞。
3. 读返回0:当写端关闭,从管道中读数据,若管道中有数据,则读到数据;
若管道中没有数据,read则返回0,不再阻塞。
4. 管道破裂:读端关闭,向管道中写入数据,发生管道破裂(异常)

1)有名管道本质:
内核空间的一段缓冲区,但这块缓冲区和一个管道文件相关联。
2)有名管道的操作流程:
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
练习:
一个进程负责从终端读取字符串,通过有名管道共享给另外一个进程,该进程负责打印数据。
//read
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
int main(int argc,const char *argv[])
{
int ret = mkfifo("./myfifo",0664);
if(ret < 0 && errno != EEXIST)
{
perror("mkfifo error");
return -1;
}
int fd = open("./myfifo",O_RDONLY);
if(fd < 0)
{
perror("open error");
return -1;
}
char buff[1024] = {0};
ssize_t cnt =read(fd,buff,sizeof(buff));
printf("cnt = %ld\n buff = %s\n",cnt,buff);
close(fd);
remove("./myfifo");
return 0;
}
write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
int main(int argc,const char *argv[])
{
int ret = mkfifo("./myfifo",0664);
if(ret < 0 && errno != EEXIST)
{
perror("mkfifo error");
return -1;
}
int fd = open("./myfifo",O_WRONLY);
if(fd < 0)
{
perror("open error");
return -1;
}
char buff[1024] = {0};
fgets(buff,sizeof(buff),stdin);
write(fd,buff,strlen(buff));
close(fd);
return 0;
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)