进程间各种通信方式的C++实现

一、信号Signal
信号是软中断,用于通知接受进程某个事件发生。一个进程可以发送信号给另一个进程,接受进程可以注册信号处理函数来相应信号。信号通常用于接收进程某个进程操作完成或异常事件发生

//发送信号
kill(pid,  SIG);
//信号处理函数
void handler(int sig){
	cout << "received signal" << endl;
}
//设置信号处理函数
signal(SIG, handler);

二、管道Pipe
管道是连接进程的无名管道,用于进程之间的通信。管道有读端和写端,一个进程往管道写端写入数据,另一个进程从读端读取信号。管道通常用于父子进程间通信

//创建管道
int pipefd[2];
pipe(pipefd);
//父进程写入管道
write(pipefd[1], "hello", 6);
//子进程从管道读取
char buf[6];
read(pipefd[0], buf, 6);

三、消息队列(Message Queue)
发送者进程可以向消息队列中添加消息,接受者进程可以从消息队列中获取消息。消息队列内的消息按发送顺序排列,接受方以FIFO的顺序获取消息。

//创建消息队列
mqd_t mq;
mq = mq.open("/mq", 0_CREAT);
//发送消息
mq_send(mq, "Hello", 6, 0);
//接受消息
char buf[6]
mq_receive(mq, buf, 6, NULL);

四、共享内存Shared Memory
共享内存是一块可由多个进程读写的内存区域。进程可以向共享内存写入数据,其他进程可以读取共享内存中的数据。共享内存适用于传输较大的数据量,因为它在进程间共享物理内存区域

//创建共享内存
int shm = shm_open("/shm", 0_CREAT, 0666);
//映射到进程地址空间
void *addr = mmap(0, 4096, PORT_WRITE, MAP_SHARED, shm, 0);
//写入共享内存
strcpy(addr, "Hello");
//读取共享内存
char* str = (char*)addr;
cout << str << endl; 

五、命名管道Named Pipe
命名管道是基于文件系统的管道,他提供一个文件作为进程间通信的通道。读进程打开该文件进行读,写进程打开该文件进行写,两端进程就可以通过该文件进行通信。命名管道也是FIFO先入先出

//创建命名管道
mkfifo("/tmp/fifo", 0666);
//打开命名管道
int fd = open("/tmp/fifo", 0_RDWR);
//写入管道
write(fd, "Hello", 6);
//读取管道
char buf[6];
read(fd, buf, 6);

六、套接字
不同进程甚至不同主机上的进程可以利用套接字进行网络通信
其实现具体步骤如下:
1、使用socket()创建一个套接字,指定通信协议族为IPv4(AF_INET),使用面向连接的TCP(SOCK_STREAM)
2、使用bind()将套接字绑定到本地地址127.0.0.1和端口8000
3、使用listen()使套接字进入监听状态,指定最大连接请求队列为5
4、使用accept()接受客户端连接,产生一个全新的套接字clientfd用于与客户端通信
5、使用read()/write()与客户端进行读写操作
6、使用close()关闭两个套接字

#include 
#include 
#include 

int main()
{
	//创建套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	//绑定套接字到本地地址和端口
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8000);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	bind(sockfd, (struct sockaddr*)&addr, sizeof(sddr));
	//监听连接
	listen(sockfd, 5);
	//接受客户端连接
	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);
	int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
	//与客户端通信
	char buf[256];
	read(clientfd, buf, sizeof(buf));
	pintf("Message from client:%s\n", buf);
	write(clientfd, "Hello from server!", 18);
	//关闭套接字
	close(sockfd);
	close(clientfd);
	return 0;
}

七、信号量
通过这种机制,可以实现对共享资源的互斥访问和同步。信号量是进程/线程间通信的一种重要机制,广泛应用于资源竞争的控制与管理。
1、 调用sem_init()初始化一个信号量,将其初始化为1,表示有一个资源。
2、 当线程调用sem_wait()时,如果信号量值>0,则信号量值减1,线程继续执行;如果信号量值为0,则线程被阻塞。
3、 当线程执行完访问临界资源的操作后,调用sem_post()将信号量值加1,唤醒被阻塞的线程。
4、 调用sem_destroy()来销毁信号量。

#include 
#include 

sem_t mutex; // 声明一个信号量

void func1() {
    sem_wait(&mutex); // 锁定信号量
    printf("func1...\n");
    sleep(3);
    sem_post(&mutex); // 解锁信号量
}

void func2() {
    sem_wait(&mutex); 
    printf("func2...\n");
    sem_post(&mutex); 
}

int main() {
    // 初始化信号量
    sem_init(&mutex, 0, 1);  

    for (int i = 0; i < 3; i++) {
        // 创建线程执行func1和func2
        pthread_t tid1, tid2;
        pthread_create(&tid1, NULL, (void*)func1, NULL);
        pthread_create(&tid2, NULL, (void*)func2, NULL);
    }
    
    // 销毁信号量
    sem_destroy(&mutex);
} 

八、事件
进程可以通过向事件对象发送或等待事件,实现进程同步和通信。
1、 设置一个标志量ready表示事件是否就绪,初始化为false。
2、 线程func1调用cv.wait()等待事件,当ready变为true时被唤醒。
3、 线程func2在准备好后,将ready置为true,然后调用cv.notify_one()唤醒一个等待线程。
4、 通过t1.join()t2.join()等待两个线程结束。
条件变量是一种广泛使用的线程同步工具,它可以使线程在等待某个条件满足时休眠,一旦条件满足其他线程可以唤醒等待线程。

#include 
#include  
#include 

std::mutex mutex;
std::condition_variable cv;
bool ready = false;

void func1() {
    std::unique_lock<std::mutex> lk(mutex);
    printf("func1 waiting...\n");
    cv.wait(lk, []{return ready;});  // 等待事件
    printf("func1...\n"); 
}

void func2() {
    printf("func2 ...\n");
    {
        std::lock_guard<std::mutex> lk(mutex);
        ready = true;
    }
    cv.notify_one();  // 通知一个线程 
}

int main() {
    std::thread t1(func1);
    std::thread t2(func2);
    
    t1.join(); 
    t2.join();
}

你可能感兴趣的:(机试面经,c++,开发语言)