Interprocess communications, inter-thread communication between the c ++ thread communication

Interprocess communication switched   https://www.cnblogs.com/LUO77/p/5816326.html

Inter-thread communication   https://www.cnblogs.com/jobs1/p/10784021.html

Inter-thread communication 

 

The difference between processes and threads

Program is just an ordered set of instructions, meaning it does not have any running, it's just a static entity . The process is different, it is to run on a data set. Process is a dynamic entity , it has its own life cycle. It is due to create and produce, due to scheduling and running, waiting for resources or events are in a wait state, and is due to complete the task undone. All reflect the dynamic process of a program running on a given data set.

Process: concurrent execution of the program is the basic unit of allocation and management of resources in the implementation process, it is a dynamic concept, the basic unit of competition in the computer system resources.

Thread: is a process of execution units, medical scheduling is the process entity. Smaller than the process of the basic unit independently. Thread is also known as lightweight processes.

A program of at least one process, a process at least one thread.

Why is there a thread?

  Each process has its own address space, that process space, in the network or multi-user switch, a server typically needs to receive a large number of uncertain number of users of concurrent requests, each request to create a process for the obviously does not work (system large overhead inefficient response to user requests), thus introducing the concept of operating system threads.

  • Execution thread is linear, although the middle will be interrupted or suspended, but the process with the resources only for the process to change the line execution services, in the event thread switching, these resources need to be protected.
  • Process is divided into single-threaded process and multi-threaded process, single-threaded process macro point of view is only a single linear execution during the execution of the micro. Macro multithreaded process is linear, perform operations on multiple microscopic.

Change process changes represent CPU threads of execution, but no change in resource processes have occurred. 

Process threads difference:

  • Address space: between threads in the same process of sharing this process's address space, and the process is a separate address space.
  • Resources have: resources such as memory, I / O, cpu and other threads share of this process in the same process, but resources between processes are independent.

     After a process crashes, it will not have an impact on other processes in protected mode, but a collapse of the entire process threads are dead. So multi-process multi-threaded robust than others.

     When switching process, resource consumption, high efficiency. So when it comes to frequent switching, better use threads within a process. Similarly, if requested at the same time and have to share the concurrent operation of certain variables can only be used with the thread can not process

  • Execution: each individual process inlet path running a sequence program execution sequence and the inlet. But the thread can not execute independently, it must exist according to the application, providing multiple execution threads controlled by the application.
  • A thread is the basic unit of processor scheduling, but the process is not.
  • Both can execute concurrently.

Advantages and disadvantages:

  Thread execution overhead is small, but not conducive to the management and protection of resources. Threads to run on SMP machines (dual-CPU system).

  Process execution overhead large, but can be a good resource management and protection. The process can span the machine forward.

When to use multi-process, when to use multithreading?

High resource management and protection requirements, does not limit the costs and efficiency, the use of multiple processes.

High efficiency requirements, frequent switching, time required resource protection and management is not very high, use multiple threads.

 

Interprocess communication

multi-Progress:

First of all, the first fork after speaking about what happened.

The new process created by fork is called the child process (child process). This function is called once but returns twice. The difference between the two is the return of the child process the return value is 0 , and returns the value of the parent process is the process of new process (child process) of the id. The reason for the child returned to the parent process id is: a child process because the process can be more than one, not a function of the process so that a process can obtain all of its child processes id . A child process, the reason fork returns 0 to it, because it can be called at any time getpid () to get their pid; can also call getppid () to get the id of the parent process . (Process id 0 is always used by the exchange process, so the process is a child process id, not 0).

After the fork, the operating system will be an exact copy of the parent process child process, although the father-son relationship, but it seems in the operating system, they are more like brother relationship, the two processes share code space, but the data are independent of space , the contents of the child data space is a complete copy of the parent process, is also the same as the instruction pointer, the child has a parent process is currently running to the position of ( the program counter pc is the same as the value of two processes, i.e., from the child process is fork return at the beginning of execution ), but a little different, if successful fork, the child process fork return value is 0, the parent process fork return value is the process ID of the child process, if the fork is unsuccessful, the parent process returns an error .
In this way you can imagine, two processes have been running at the same time, and in unison, after the fork, they were as different jobs, which is the bifurcation. This is also the reason why it's called a fork fork

As for a first run, it may be related to the operating system (scheduling algorithm), but also to the issue is not important in practical applications, if needed parent and child collaboration, can be resolved by way primitive.


 

Common means of communication:

1. Pipeline pipe: pipe is half-duplex communication mode, data flows only one way, but can only be used in a process having a genetic relationship between. Kinship process usually refers to the process of parent-child relationship.
2. Named Pipes FIFO: named pipe is half-duplex communication, but it allows communication between unrelated processes.
4. The message queue MessageQueue: message queue is a linked list of messages, by message stored in the kernel queue identifier. Signaling message queue overcome the less information, only the carrier pipe plain byte stream buffer size is limited, and other shortcomings.
5. Shared storage SharedMemory: Shared memory is memory mapped a period that can be accessed by other processes, this shared memory created by a process, but can be accessed by multiple processes. IPC shared memory is the fastest way, it is for the other inter-process communication running low efficiency specifically designed. It is often associated with other communication mechanisms, such as two signals, used in conjunction to achieve synchronization and communication between processes.
6. Semaphore Semaphore: Semaphore is a counter, multiple processes can be used to control access to shared resources. It is often used as a locking mechanism to prevent access to shared resources is a process, other processes can also access the resource. Therefore, the main as well as inter-process synchronization means between the different threads within the same process.
7. Socket Socket: Solutions sleeve port is an inter-process communication mechanism, with various other communication mechanism is that it can be used for interprocess communication between its different.
8. Signal (sinal): Signal is a more sophisticated means of communication, an event used to notify the receiving process has occurred.

 

signal:

Signal Linux system is a mechanism for interprocess communication between or operation, signals may be transmitted at any given time to process, without having to know the status of the process. If the process is not being executed, the signal is saved by the kernel up, know that the process resumes execution and passed to him so far. If a signal is set to block the process, then it passes the signal is delayed, is passed to the process when the obstruction until it is canceled.

 

Linux offers dozens of signals, each representing a different meaning. Rely on their values ​​to distinguish between signals, but usually use a signal name in a program to represent a signal. In the Linux system, and these signals to their name named constants are defined in /usr/includebitssignum.h file. Typically contains program directly <signal.h> like.

 

Is an analog signal to interrupt mechanism in the software level, is an asynchronous communication, the signal can interact directly between user space and kernel processes. Kernel can also use a signal to notify the user-space process to notify users of system events which occurred in space. Signal events from two sources:

1) the source of the hardware, such as pressing the cltr + C, typically generates an interrupt signal sigint

2) the software source, for example using a system call or command signals. The most commonly used system is a function of the transmission signal kill, raise, setitimer, sigation, sigqueue function. Source software also includes a number of illegal operations and other operations.

 

Once a signal is generated, there are three ways a corresponding user process signals generated:

1) perform a default action, linux signals for each specified default action.

2) capture signal, the signal processing function is defined, when the signal occurs, executes the corresponding handler.

3) ignore the signal, when the received signal does not want to perform an impact on the process, and let the process continue, you can ignore the signal, that is, the process does not signal any treatment.

  There are two application processes are unable to capture the signal and ignore that SIGKILL and SEGSTOP, which is to enable the system administrator can interrupt or end of a particular process at any time.

The figure represents a common Linux commands

1, a signal transmission:

The key signal transmission allows the system to send a signal to know what process and what signal is sent. The following is the operation signal common functions:

Example: create a child process, in order to make the child not the parent process before issuing signal the end to send sigstop signal the child process to use the raise function, make yourself pause; parent process uses the signal operation kill function, sending sigkill signal to the child process, the child process this signal is received, the end of the child process.

2, the signal processing

当某个信号被发送到一个正在运行的进程时,该进程即对次特定的信号注册相应的信号处理函数,以完成所需处理。设置信号处理方式的是signal函数,在程序正常结束前,在应用signal函数恢复系统对信号的

默认处理方式。

3.信号阻塞

有时候既不希望进程在接收到信号时立刻中断进程的执行,也不希望此信号完全被忽略掉,而是希望延迟一段时间再去调用信号处理函数,这个时候就需要信号阻塞来完成。

 

例子:主程序阻塞了cltr+c的sigint信号。用sigpromask将sigint假如阻塞信号集合。

 

管道:

管道允许在进程之间按先进先出的方式传送数据,是进程间通信的一种常见方式。

管道是Linux 支持的最初Unix IPC形式之一,具有以下特点:

1) 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

2) 匿名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

3) 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

 

管道分为pipe(无名管道)和fifo(命名管道)两种,除了建立、打开、删除的方式不同外,这两种管道几乎是一样的。他们都是通过内核缓冲区实现数据传输。

  • pipe用于相关进程之间的通信,例如父进程和子进程,它通过pipe()系统调用来创建并打开,当最后一个使用它的进程关闭对他的引用时,pipe将自动撤销。
  • FIFO即命名管道,在磁盘上有对应的节点,但没有数据块——换言之,只是拥有一个名字和相应的访问权限,通过mknode()系统调用或者mkfifo()函数来建立的。一旦建立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。

管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。

无名管道:

pipe的例子:父进程创建管道,并在管道中写入数据,而子进程从管道读出数据

命名管道:

和无名管道的主要区别在于,命名管道有一个名字,命名管道的名字对应于一个磁盘索引节点,有了这个文件名,任何进程有相应的权限都可以对它进行访问。

而无名管道却不同,进程只能访问自己或祖先创建的管道,而不能访任意访问已经存在的管道——因为没有名字。

 

Linux中通过系统调用mknod()或makefifo()来创建一个命名管道。最简单的方式是通过直接使用shell

mkfifo myfifo

 

 等价于

mknod myfifo p

 

以上命令在当前目录下创建了一个名为myfifo的命名管道。用ls -p命令查看文件的类型时,可以看到命名管道对应的文件名后有一条竖线"|",表示该文件不是普通文件而是命名管道。

使用open()函数通过文件名可以打开已经创建的命名管道,而无名管道不能由open来打开。当一个命名管道不再被任何进程打开时,它没有消失,还可以再次被打开,就像打开一个磁盘文件一样。

可以用删除普通文件的方法将其删除,实际删除的事磁盘上对应的节点信息。

例子:用命名管道实现聊天程序,一个张三端,一个李四端。两个程序都建立两个命名管道,fifo1,fifo2,张三写fifo1,李四读fifo1;李四写fifo2,张三读fifo2。

用select把,管道描述符和stdin假如集合,用select进行阻塞,如果有i/o的时候唤醒进程。(粉红色部分为select部分,黄色部分为命名管道部分)

 

 

 

在linux系统中,除了用pipe系统调用建立管道外,还可以使用C函数库中管道函数popen函数来建立管道,使用pclose关闭管道。

例子:设计一个程序用popen创建管道,实现 ls -l |grep main.c的功能

分析:先用popen函数创建一个读管道,调用fread函数将ls -l的结果存入buf变量,用printf函数输出内容,用pclose关闭读管道;

接着用popen函数创建一个写管道,调用fprintf函数将buf的内容写入管道,运行grep命令。

popen的函数原型:

FILE* popen(const char* command,const char* type);

 

参数说明:command是子进程要执行的命令,type表示管道的类型,r表示读管道,w代表写管道。如果成功返回管道文件的指针,否则返回NULL。

使用popen函数读写管道,实际上也是调用pipe函数调用建立一个管道,再调用fork函数建立子进程,接着会建立一个shell 环境,并在这个shell环境中执行参数所指定的进程。

消息队列:

消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。

消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。

可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

消息队列的常用函数如下表:

进程间通过消息队列通信,主要是:创建或打开消息队列,添加消息,读取消息和控制消息队列。

例子:用函数msget创建消息队列,调用msgsnd函数,把输入的字符串添加到消息队列中,然后调用msgrcv函数,读取消息队列中的消息并打印输出,最后再调用msgctl函数,删除系统内核中的消息队列。(黄色部分是消息队列相关的关键代码,粉色部分是读取stdin的关键代码)

共享内存:

共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。

 

采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。

一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建立共享内存区域;而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件,因此,采用共享内存的通信方式效率非常高。

共享内存有两种实现方式:1、内存映射 2、共享内存机制

1、内存映射

内存映射 memory map机制使进程之间通过映射同一个普通文件实现共享内存,通过mmap()系统调用实现。普通文件被映射到进程地址空间后,进程可以

像访问普通内存一样对文件进行访问,不必再调用read/write等文件操作函数。

例子:创建子进程,父子进程通过匿名映射实现共享内存。

分析:主程序中先调用mmap映射内存,然后再调用fork函数创建进程。那么在调用fork函数之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap函数的返回地址,这样,父子进程就可以通过映射区域进行通信了。

2、UNIX System V共享内存机制

IPC的共享内存指的是把所有的共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。

和前面的mmap系统调用通过映射一个普通文件实现共享内存不同,UNIX system V共享内存是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信。

例子:设计两个程序,通过unix system v共享内存机制,一个程序写入共享区域,另一个程序读取共享区域。

分析:一个程序调用fotk函数产生标准的key,接着调用shmget函数,获取共享内存区域的id,调用shmat函数,映射内存,循环计算年龄,另一个程序读取共享内存。

(fotk函数在消息队列部分已经用过了,

根据pathname指定的文件(或目录)名称,以及proj参数指定的数字,ftok函数为IPC对象生成一个唯一性的键值。)

key_t ftok(char* pathname,char proj)

 

c++ 线程间通信方式

 

一:两个进程间的两个线程通信,相当于进程间通信

二:一个进程中的两个线程间通信

  通信方式:

1.互斥锁

  mutex;

  lock_guard (在构造函数里加锁,在析构函数里解锁)

  unique_lock 自动加锁、解锁

 

2.读写锁

  shared_lock

3.信号量

  c++11中未实现,可以自己使用mutex和conditon_variable 实现

  代码实现如下: 

#pragma once
#include <mutex>
#include <condition_variable>
class Semaphore
{
public:
 explicit Semaphore(unsigned int count); //用无符号数表示信号量资源 
 ~Semaphore();
public:
 void wait();
 void signal();
private:
 int m_count; //计数器必须是有符号数 
 std::mutex m_mutex;
 std::condition_variable m_condition_variable;
};
 
#include "Semaphore.h"
Semaphore::Semaphore(unsigned int count) :m_count(count) {
}
Semaphore::~Semaphore()
{
}
void Semaphore::wait() {
 std::unique_lock<std::mutex> unique_lock(m_mutex);
 --m_count;
 while (m_count < 0) {
  m_condition_variable.wait(unique_lock);
 }
}
void Semaphore::signal() {
 std::lock_guard<std::mutex> lg(m_mutex);
 if (++m_count < 1) {
  m_condition_variable.notify_one();
 }
}

4.条件变量

  condition_variable

 

一:两个进程间的两个线程通信,相当于进程间通信

二:一个进程中的两个线程间通信

  通信方式:

1.互斥锁

  mutex;

  lock_guard (在构造函数里加锁,在析构函数里解锁)

  unique_lock 自动加锁、解锁

 

2.读写锁

  shared_lock

3.信号量

  c++11中未实现,可以自己使用mutex和conditon_variable 实现

  代码实现如下: 

#pragma once
#include <mutex>
#include <condition_variable>
class Semaphore
{
public:
 explicit Semaphore(unsigned int count); //用无符号数表示信号量资源 
 ~Semaphore();
public:
 void wait();
 void signal();
private:
 int m_count; //计数器必须是有符号数 
 std::mutex m_mutex;
 std::condition_variable m_condition_variable;
};
 
#include "Semaphore.h"
Semaphore::Semaphore(unsigned int count) :m_count(count) {
}
Semaphore::~Semaphore()
{
}
void Semaphore::wait() {
 std::unique_lock<std::mutex> unique_lock(m_mutex);
 --m_count;
 while (m_count < 0) {
  m_condition_variable.wait(unique_lock);
 }
}
void Semaphore::signal() {
 std::lock_guard<std::mutex> lg(m_mutex);
 if (++m_count < 1) {
  m_condition_variable.notify_one();
 }
}

4.条件变量

  condition_variable

Guess you like

Origin www.cnblogs.com/yi-mu-xi/p/11024997.html