linux进程间通信如何加锁
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux进程间通信如何加锁相关的知识,希望对你有一定的参考价值。
参考技术A进程间通信有一种[共享内存]方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?
关于进程间的通信方式估计大多数人都知道,这也是常见的面试八股文之一。
个人认为这种面试题没什么意义,无非就是答几个关键词而已,更深入的可能面试官和面试者都不太了解。
关于进程间通信方式我之前在【这篇文章】中有过介绍,感兴趣的可以移步去看哈。
进程间通信有一种[共享内存]方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?
我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?
我找到了两种方法,信号量和互斥锁。
直接给大家贴代码吧,首先是信号量方式:
代码中的MEOW_DEFER,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个:
具体含义大家应该看名字就知道,这里的重点就是sem_init中的pshared参数,该参数为1表示可在进程间共享,为0表示只在进程内部共享。
第二种方式是使用锁,即pthread_mutex_t,可是pthread_mutex不是用作线程间数据竞争的吗,怎么能用在进程间呢?
可以给它配置一个属性,示例代码如下:
它的默认属性是进程内私有,但是如果给它配置成PTHREAD_PROCESS_SHARED,它就可以用在进程间通信中。
相关视频推荐
360度无死角讲解进程管理,调度器的5种实现
Linux进程间通信-信号量、消息队列和共享内存
学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括 C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg 等),免费分享
完整代码如下:
我想这两种方式应该可以满足我们日常开发过程中的大多数需求。
锁的方式介绍完之后,可能很多朋友自然就会想到原子变量,这块我也搜索了一下。但是也不太确定C++标准中的atomic是否在进程间通信中有作用,不过看样子boost中的atomic是可以用在进程间通信中的。
其实在研究这个问题的过程中,还找到了一些很多解决办法,包括:
Disabling Interrupts
Lock Variables
Strict Alternation
Peterson\'s Solution
The TSL Instruction
Sleep and Wakeup
Semaphores
Mutexes
Monitors
Message Passing
Barriers
这里就不过多介绍啦,大家感兴趣的可以自行查阅资料哈。
概述Linux进程间通信方式
在现代计算机上,一个任务的完成,往往需要多个进程协调,这时进程间如何交流就成了必须解决的问题。实现进程间通信(IPC)有很多方法,下面简单介绍一下各个通讯方式的原理,不讲具体代码实现。
管道
管道一般指无名管道(还有另一种叫有名管道),是Unix系统最古老的进程通信方式。管道通信有以下特点:
• 管道是半双工的,单向的,同一时刻只能允许一方向另一方发送;
• 管道只能在有父子进程,或者兄弟进程之间使用;
创建管道的函数原型:int pipe(int fd[2]);
管道利用两个标识符进行读写控制,fd[0]用于控制读,fd[1]用于控制写。如下图,管道创建后所有标识符都打开状态,如要实现A向B传递数据,则需要关闭A的fd[0],关闭B的fd[1]。
值得一提的是,管道概念在linux的shell中也用到,管道符\'|\',也是利用了管道的抽象,进行输出重定向,将一条命令的输出传递给另一条命令作为其输入。
有名管道FIFO
和上面的无名管道类似,不过有名管道可以在无关的进程之间交换信息。
有名管道的创建函数原型如下:int mkfifo(const char *_path,mode_t mode);管道文件的path就是它的名字,Linux上一切都是文件,有名管道也不例外,它是设备文件。
利用有名管道进行通信的步骤大概是这样:
创建一个有名管道文件 -> 进程A用文件write()操作发送消息到管道 -> 进程B用文件read()操作从管道读取消息。
信号
像我们常用ctrl+c来结束当前进程,就是通过shell发送了一个SIGINT信号。linux一共提供了64个信号,它们的编号从1到64。使用$man 7 signal命令可以查看每种信号的名称、编号、作用。
发送端如何发送信号
• 硬件产生信号,如我们键盘组合命令可以产生信号,硬件的故障也可能产生信号;
• 软件发送信号,最常用的信号发送函数为kill,指定信号类别和目标进程id就可以发送信号。除了kill,还有sigqueue、raise等也能产生信号。
接收端如何处理信号
• 忽略信号,不对信号做任何处理;
• 执行默认处理程序,每个信号都有自己默认的处理函数;
• 执行指定的处理函数,我们可以将信号和自定义的处理函数进行绑定(也可以说是注册一种信号处理函数),这样接收端会优先执行自定义的信号处理函数。
如何自定义处理函数
• signal(int signum,sighandler_t handler);自定义一个handler,绑定到signum信号上。
• sigaction(int signum,struct sigaction * act,struct sigaction * oldact);也可以用来注册。
消息队列
和分布式应用的消息队列类似,消息队列是异步通信的一种机制。和数据结构学到的队列一样,我们可以创建一个消息队列,发送端发送消息入队,读取端按需从队列读取信息。这样的通讯是异步的,不会造成进程阻塞。
简单归纳下消息队列和管道通信的区别:
• 消息队列是异步通信,管道是同步通信,会使进程阻塞;
• 消息队列可以在不相干进程间通信,匿名管道只能在近亲进程间通信;
• 消息队列存放在内存中,而有名管道存放在磁盘上,因此消息队列存取速度快;匿名管道在内核缓冲区理论最快,不过使用限制很多;
• 因为消息队列存在内存里,因此是以块式存取,而管道都是流式存取。
信号量
在PV操作和锁中已经学到过,信号量是用于并发时资源互斥和同步的一种机制。信号量本身不能传递数据,通常搭配共享内存一同使用。
顾名思义,信号量指的就是信号(资源)的数量。
假如资源数是1,那么信号量初始值s=1;当没有进程访问资源时,即资源空闲时,s=1;这时有一个进程申请访问,执行一次P操作,信号量减一,s=0;紧接着又来了一个进程想用资源,因为s<=0,资源非空闲,它就要等;等到上一个进程用完了,退出时会执行V操作,将信号量加一,这时等待使用的进程发现,s=1了,他就可以进入使用了。
共享内存
顾名思义,即进程之间共享一段内存区域。共享内存理论上是最快的IPC方法,因为其直接对内存的数据进行操作。多个进程不能同时读写一个数据,需要进行同步,而共享内存的系统调用中并未实现同步,需要我们借助信号量机制实现同步。因此共享内存常常和信号量结合使用。
Socket套接字
Socket是否还有印象?在学习计算机网络时我们经常遇见它,它是一种在不同主机的进程间进行网络通信的机制。除了这种网络套接字外,还有一种叫IPC套接字,特指用于同一主机进程间通信的方式。在这几种IPC之中,套接字通信是功能最强大的,也是最为复杂的一种。
本文仅仅是对进程间通信方式的总结概述,并未详尽。文中如有错误之处,望网友指正。
以上是关于linux进程间通信如何加锁的主要内容,如果未能解决你的问题,请参考以下文章