linux高级编程:线程(二)、进程间的通信方式

线程:

回顾线程(一):

1.线程间通信问题

   线程间共享同一个资源(临界资源)

   互斥:

        排他性访问

        linux系统 -- 提供了Posix标准的函数库 -- 互斥量(互斥锁)

   原子操作:---

   机制:

        加锁 -- 解锁

        锁 --- 操作系统 --- (实现的机制,需要操作系统来

        | - 加锁 -- 用户态 -- 切换到(耗时) -- 内核态 -- 获得了 -- 内核态 -- 用户态 -- 解锁 |

   函数:

        pthread_mutex_t mutex;

        pthread_mutex_init();

        pthread_mutex_lock();

        pthread_mutex_trylock();    //  尝试获得锁,若没获得则返回非0值。

                

        pthread_mutex_unlock();

        pthread_mutex_destroy();

线程的同步:

      

        同步 ==》有 一定先后顺序的 对资源的排他性访问。

        要同步的原因:互斥锁可以控制排他访问但没有次序。
    
        信号量 --- 实现线程间的同步.
    
        来源  生活 --- 交通信号灯

信号量的分类:


        1、无名信号量 ==》线程间通信
        2、有名信号量 ==》进程间通信

同步机制:

        信号量(个数) --- 反映的是资源的数量

        考虑的时候,站在使用这的角度考虑

        站在a的角度考虑。。。。。。

框架:

        1. 信号量的定义       sem_t  sem  //造了一类资源
        2. 信号量的初始化   sem_init 
        3. 信号量的PV操作 (核心) sem_wait()/ sem_post()
        4. 信号量的销毁。   sem_destroy

  

信号量函数:

1、定义

sem_t 名字;

2、初始化

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

        功能:

                将已经定义好的信号量赋值。

        参数:

                @sem 要初始化的信号量

                @pshared

                        pshared = 0 ;表示线程间使用信号量(一般填这个)

                        !=0 ;表示进程间使用信号量

                @value:

                        信号量的初始值,一般无名信号量(一开始的资源的个数)

                        都是二值信号量,0 1

                        0 表示红灯,进程暂停阻塞

                        1 表示绿灯,进程可以通过执行

                        也可以是多个,变成计数信号量

                返回值:

                        成功 0,失败 -1;

3、PV操作

int sem_wait(sem_t *sem); //p操作

        功能:

                判断当前sem信号量是否有资源可用。

                如果sem有资源(==1),则申请该资源,程序继续运行

                如果sem没有资源(==0),则线程阻塞等待,一旦有资源

                则自动申请资源并继续运行程序。

                消耗了这个sem,就没有了

             注意:sem 申请资源后会自动执行 sem = sem - 1;

        参数:

                @sem 要判断的信号量资源

                返回值:

                        成功 0 ,失败 -1

int sem_post(sem_t *sem); //V操作

        功能:

                函数可以将指定的sem信号量资源释放

                并默认执行,sem = sem+1;

                线程在该函数上不会阻塞。

                产生了这个sem就有了,可以由wait(sem)接受去消耗

                参数:

                @sem 要释放资源的信号量

                返回值:

                        成功 0,失败 -1;

4、销毁

int sem_destroy(sem_t *sem);

练习:   hello world
#include<stdio.h>
#include<semaphore.h>
#include<errno.h>
#include<pthread.h>
#include<stdlib.h>

sem_t sem_h;
sem_t sem_w;

void *do_hello(void *arg)
{
	while(1)	
	{
		sem_wait(&sem_h);
		printf("hello ");
		sem_post(&sem_w);
	}
	return NULL;
}

void *do_world(void *arg)
{
	while(1)	
	{
		sem_wait(&sem_w);
		printf("world\n");
		sem_post(&sem_h);
	}
	return NULL;

}
typedef void *(*threadF_t)(void *);
int main(int argc, const char *argv[])
{
	int i;
	pthread_t tid[i];
	threadF_t pFunc[2] = {do_hello,do_world};

	sem_init(&sem_h,0,1);
	sem_init(&sem_w,0,0);

	for(i = 0;i < 2;++i)
	{
		int ret = pthread_create(&tid[i],NULL,pFunc[i],NULL);
		if(ret != 0)
		{
			errno = ret;
			perror("pthread_create fail");
			exit(EXIT_FAILURE);
		}
	}

	sem_destroy(&sem_h);
	sem_destroy(&sem_w);

	pthread_detach(tid[0]);
	pthread_detach(tid[1]);

	printf("---main----exit\n");
	pthread_exit(NULL);

	return 0;
}

进程间的通信方式:

三大类:

1.同主机   ---- 基于内存的 
         

 古老的通信方式 
                    //管道  ---- 
                             无名管道  
                             有名管道
                    //信号  
    
          IPC对象通信(改进)
                     消息队列(用的相对少,这里不讨论)
                     共享内存(*) //最高效 
                     信号量集() //信号量  

 
2.     

        //不同主机 、多台主机
          socket //网络部分 
  
        //同一主机
        2.1、古老的通信方式
                管道:
                           无名管道  
                           有名管道  
                           信号

        2.2、IPC对象通信 system v    BSD     suse fedora   kernel.org
                消息队列(用的相对少,这里不讨论)
                共享内存(*) //最高效 
                信号量集() //信号量  


        //不同主机 


3、socket通信

        网络通信

 

1、pipe  无名管道

使用框架:

                创建管道 ==》读写管道 ==》关闭管道

1、无名管道 ===》管道的特例 ===>pipe函数
    特性:
            1.1  亲缘关系进程使用
            1.2  有固定的读写端

   

流程:
    创建并打开管道: pipe函数
    

函数:

    #include <unistd.h>
    int pipe(int pipefd[2]);
    int pipe(int *pipefd);
    int fd[2];
            功能:创建并打开一个无名管道
            参数:  @pipefd[0] ==>无名管道的固定读端//0 -- 标准输入
                         @pipefd[1] ==>无名管道的固定写端//1 -- 标准输出 
            返回值: 成功 0
                            失败 -1;

注意事项:

         1、无名管道的架设应该在fork之前进行。  

关闭管道: close();

练习:父进程输入、子进程打印

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <sys/wait.h>

int main(int argc, const char *argv[])
{
	int fd[2];
	if(pipe(fd) < 0)
	{
		perror("pipe fail");
		return -1;
	}

	char buf[100] = {0};
	int ret = 0;

	pid_t pid = fork();
	while(1)
	{
		if(pid < 0)
		{
			perror("fork fail");
			return -1;
		}
		else if(pid > 0)
		{
			close(fd[0]);

			printf(">");
			fflush(stdout);
			ret = read(0,buf,sizeof(buf));
			buf[ret] = '\0';
			write(fd[1],buf,strlen(buf) + 1);
			if(strncmp(buf,"quit",4) == 0)
			{
				wait(NULL);
				close(fd[1]);
				return 0;
			}
		}
		else if(pid == 0)
		{
			close(fd[1]);
			ret = read(fd[0],buf,sizeof(buf));
			printf("date = %s\n",buf);
			if(strncmp(buf,"quit",4) == 0)
			{
				close(fd[0]);
				exit(0);
			}
		}
	}
	return 0;
}

管道的读写规则:
   

    1.读端存在,写管道
         管道空:可以写数据
         管道满:会造成-->写阻塞 
      
    2.读端不存在,写管道
         系统会给进程发一个信号SIGPIPE(管道破裂)

    3.写端存在,读管道
         管道空,读不到数据,
         这时会造成读操作阻塞

    4.写端不存在,读管道 
         如果管道中有数据,则读取这些数据!
         如果没有数据,读操作不阻塞,立即返回!

2、fifo有名管道

有名管道===》fifo ==》有文件名称的管道。
                                                                      文件系统中可见

框架:

    (1).创建有名管道 -- 类似 文件 (管道文件) 
    (2).打开有名管道 -- open 
    (3).读写管道     -- read/write 
    (4).关闭管道  ==》卸载有名管道 //close  

1、创建:mkfifo     //创建了一个有名管道

#include <sys/types.h>
#include <sys/stat.h>
 remove();

int mkfifo(const char *pathname, mode_t mode);

        功能:
                      在指定的pathname路径+名称下创建一个权限为
                      mode的有名管道文件。
        参数:@pathname要创建的有名管道路径+名称
                      mode  8进制文件权限。
        返回值:  成功 0
                        失败  -1;

2、打开有名管道 open

注意:该函数使用的时候要注意打开方式,
    因为管道是半双工模式,所有打开方式直接决定


    当前进程的读写方式。
    一般只有如下方式:
    int fd-read = open("./fifo",O_RDONLY); ==>fd 是固定读端    //阻塞,只有双方以对应的方式打开的时候才会
    int fd-write = open("./fifo",O_WRONLY); ==>fd 是固定写端   
    不能是 O_RDWR 方式打开文件。
    不能有 O_CREAT 选项,因为创建管道有指定的mkfifo函数
    
    有名管道打开:
    注意,
    如果一端是以只读,或者只写方式打开的。
    程序会阻塞,
    阻塞在打开操作。
    直到另一端,以只写或只读方式打开。
    A.c --- 只读 
    B.c --- 只写 

练习:实现双向通信:

        打开两个有名通道文件

// a
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>



int main(int argc, const char *argv[])
{

	if (mkfifo("a_2_b",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	if (mkfifo("b_2_a",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}

	int fd_w = open("a_2_b",O_WRONLY);
	if (fd_w< 0)
	{
		perror("open fail");
		return -1;
	}

	int fd_r = open("b_2_a",O_RDONLY);
	if (fd_r< 0)
	{
		perror("open fail");
		return -1;
	}


	pid_t pid = fork();
	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	char buf[1024] = {0};
	if (pid > 0)
	{
		while (1)
		{
			printf(">");
			fflush(stdout);
			fgets(buf,sizeof(buf),stdin);
			write(fd_w,buf,strlen(buf)+1);

			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd_w);
				close(fd_r);
			}
		}

	}else if (pid == 0)
	{
		while (1)
		{
			printf("<");
			int ret = read(fd_r,buf,sizeof(buf));
			printf("ret = %d: %s\n",ret,buf);
		}

	}

	return 0;
}

// b
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>



int main(int argc, const char *argv[])
{
	if (mkfifo("a_2_b",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	if (mkfifo("b_2_a",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}

	int fd_r = open("a_2_b",O_RDONLY);
	if (fd_r< 0)
	{
		perror("open fail");
		return -1;
	}
	int fd_w = open("b_2_a",O_WRONLY);
	if (fd_w< 0)
	{
		perror("open fail");
		return -1;
	}



	pid_t pid = fork();
	if (pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	char buf[1024] = {0};
	if (pid > 0)
	{
		while (1)
		{
			printf(">");
			fflush(stdout);
			fgets(buf,sizeof(buf),stdin);
			write(fd_w,buf,strlen(buf)+1);
		}

	}else if (pid == 0)
	{
		while (1)
		{
			printf("<");
			int ret = read(fd_r,buf,sizeof(buf));
			printf("ret = %d: %s\n",ret,buf);

			if (strncmp(buf,"quit",4) == 0)
			{
				close(fd_w);
				close(fd_r);
			}
		}

	}





	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/425568.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.1 简述卷积的基本操作,卷积和全连接层的区别?

1.1 简述卷积的基本操作&#xff0c;卷积和全连接层的区别&#xff1f; 摘要&#xff1a; 全连接层的输出层每个节点与输入层的所有节点连接。 卷积层具有局部连接和权值共享的特性。 问题&#xff1a;简述卷积的基本操作&#xff0c;并分析其与全连接层的区别。 分析与解答&a…

【计算机网络】深度学习HTTPS协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【计算机网络】深度学习HTTPS协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一:HTTPS是什么二:HTTPS的工作过程三:对称加密四:非对称加密五:中间人攻击1…

JAVA内存模型与JVM内存结构

注意区分Java内存模型&#xff08;Java Memory Model&#xff0c;简称JMM&#xff09;与Jvm内存结构&#xff0c;前者与多线程相关&#xff0c;后者与JVM内部存储相关。本文会对两者进行简单介绍。 一、JAVA内存模型(JMM) 1. 概念 说来话长&#xff0c;由于在不同硬件厂商和…

详解动态规划(算法村第十九关青铜挑战)

不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finis…

重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

大家好我是苏麟 , 今天开始又一个专栏开始了(又一个坑 哈哈) . 重载&#xff08;Overload&#xff09;和重写&#xff08;Override&#xff09;的区别。重载的方法能否根据返回类型进行区分&#xff1f; 方法的重载和重写都是实现多态的方式&#xff0c;区别在于前者实现的是编…

pyqt5怎么返回错误信息给页面(警告窗口)

在软件设计中&#xff0c;我们可能会遇到对异常的处理&#xff0c;有些异常是用户需要看到的&#xff0c;比如说&#xff0c;当我们登录出错的时候&#xff0c;后端需要给我们返回响应的错误信息&#xff0c;就像下图实现的这样。 类似这种效果&#xff0c;我们该如何实现&…

C++真题列表

题目解析&#xff1a;RAM是闪存&#xff0c;只要一关机一拔电&#xff0c;就会丢失数据 题目解答&#xff1a;A 题目解析&#xff1a;TXT格式是文本文档 题目解答&#xff1a;B 题目解析&#xff1a;IP地址中每一个字节的取值范围是[0~255]&#xff0c;是不可能有256的 题目…

2024最新算法:美洲狮优化算法(Puma Optimizar Algorithm ,POA)求解23个基准函数(提供MATLAB代码)

一、美洲狮优化算法 美洲狮优化算法&#xff08;Puma Optimizar Algorithm &#xff0c;POA&#xff09;由Benyamin Abdollahzadeh等人于2024年提出&#xff0c;其灵感来自美洲狮的智慧和生活。在该算法中&#xff0c;在探索和开发的每个阶段都提出了独特而强大的机制&#xf…

TDengine 在 DISTRIBUTECH 分享输配电数据管理实践

2 月 27-29 日&#xff0c;2024 美国国际输配电电网及公共事业展&#xff08;DISTRIBUTECH International 2024&#xff09;在美国-佛罗里达州-奥兰多国家会展中心举办。作为全球领先的年度输配电行业盛会&#xff0c;也是美洲地区首屈一指的专业展览会&#xff0c;该展会的举办…

干货!Python获取字典元素

1.访问字典中的元素 第一种方式&#xff1a;通过key访问 dict1 {"name":"中国医生", "author":"刘伟强", "person":"张涵予"} print(dict1["author"]) # 刘伟强 # print(dict1["price"…

八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX

目录 前言0. 简述1. camera.backbone.onnx(fp16)2. camera.backbone.onnx(int8)3. camera.vtransform.onnx(fp16)4. fuser.onnx(fp16)5. fuser.onnx(int8)6. lidar.backbone.xyz.onnx7. head.bbox.onnx(fp16)总结下载链接参考 前言 自动驾驶之心推出的《CUDA与TensorRT部署实战…

ArrayList集合源码分析

ArrayList集合源码分析 文章目录 ArrayList集合源码分析一、字段分析二、构造方法分析三、方法分析四、总结 内容如有错误或者其他需要注意的知识点&#xff0c;欢迎指正或者探讨补充&#xff0c;共同进步。 一、字段分析 //默认初始化容量。这里和Vector一样&#xff0c;只是…

Maven实战(2)之搭建maven私服

一, 背景: 如果使用国外镜像,下载速度比较慢; 如果使用阿里云镜像,速度还算OK,但是假如网速不好的时候,其实也是比较慢的; 如果没有网的情况下更加下载不了. 二, 本地仓库、个人/公司私服、远程仓库关系如下: 三, 下载安装nexus私服 略

Git 指令深入浅出【1】—— 文件管理

Git 指令深入浅出【1】—— 文件管理 一、新建仓库二、配置1. 基本指令2. 免密配置3. 简化指令 三、管理文件1. 常用文件管理指令&#xff08;1&#xff09;基本指令工作区暂存区版本库 &#xff08;2&#xff09;日志&#xff08;3&#xff09;查看修改 2. 版本回退&#xff0…

每日五道java面试题之mysql数据库篇(三)

目录&#xff1a; 第一题. 百万级别或以上的数据如何删除&#xff1f;第二题. 前缀索引第三题. 什么是最左前缀原则&#xff1f;什么是最左匹配原则?第四题. B树和B树的区别第五题. 使用B树和B树好处 第一题. 百万级别或以上的数据如何删除&#xff1f; 关于索引&#xff1a;…

奇酷网络董事长吴渔夫:以AI思维引领游戏制作,慢工出细活

文 | 大力财经 奇酷网络是一家以“AI游戏”为核心理念的创业公司&#xff0c;其独特的运营模式和理念备受瞩目。公司采用基于“AI思维”的运作方式&#xff0c;形成了与传统互联网思维鲜明对比的“超级个体公司”模式。尽管全职员工仅有两名&#xff0c;但公司CEO采取“以一打…

CPU漏洞之Spectre

一、前言 在过去的几十年里&#xff0c;一些微架构设计技术促进了处理器速度的提高。其中一个进步是推测执行(Speculative execution)&#xff0c;它被广泛用于提高性能&#xff0c;猜测CPU未来可能的执行方向&#xff0c;并提前执行这些路径上的指令。比如说&#xff0c;程序…

HarmonyOS—配置编译构建信息

在进行应用/服务的编译构建前&#xff0c;需要对工程和编译构建的Module进行设置。API Version 9、API Version 8与API Version 4~7的构建体系不同&#xff0c;因此在设置编译构建信息时也存在差异&#xff1a; API Version 9&#xff1a;需要对构建配置文件、构建脚本、应用依…

Cloud+Consul

Cloud整合Zookeeper代替Eureka-CSDN博客 Consul简介 Consul是一套开源的分布式服务发现和配置管理系统 What is Consul? | Consul | HashiCorp DeveloperConsul is a service networking solution that delivers service discovery, service mesh, and network security ca…

【C++航海王:追寻罗杰的编程之路】CC++内存管理你知道哪些?

目录 1 -> C/C内存分布 2 -> C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 3 -> C内存管理方式 3.1 -> new/delete操作内置类型 3.2 -> new和delete操作自定义类型 4 -> operator new与operator delete函数 4.1 -> operator ne…