管道demo
#include
#include
#include
#include
int main() {
int pipefd[2]; // 用于存储管道的文件描述符
pid_t pid;
// 创建管道
if (pipe(pipefd) == -1) {
exit(exit_failure);
}
// 创建子进程
pid = fork();
if (pid == -1) {
exit(exit_failure);
}
if (pid > 0) { // 父进程
// 关闭管道的写端
close(pipefd[1]);
// 从管道的读端读取数据
char buffer[128];
ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0'; // 确保字符串以 null 结尾
std::cout << "parent received: " << buffer << std::endl;
} else {
std::cerr << "failed to read from pipe" << std::endl;
}
// 关闭管道的读端
close(pipefd[0]);
} else { // 子进程
// 关闭管道的读端
close(pipefd[0]);
// 向管道的写端写入数据
const char *msg = "hello from child process!";
ssize_t bytes_written = write(pipefd[1], msg, strlen(msg));
if (bytes_written < 0) {
std::cerr << "failed to write to pipe" << std::endl;
}
// 关闭管道的写端
close(pipefd[1]);
}
return 0;
}
命名管道demo
- 创建命名管道
我们首先需要创建一个命名管道。这可以通过命令行工具 mkfifo 或在程序中使用 mkfifo() 系统调用来完成。
创建管道的命令行方式:
mkfifo /tmp/myfifo
创建管道的程序方式:
#include
#include
#include
int main() {
// 创建命名管道
if (mkfifo("/tmp/myfifo", 0666) == -1) {
perror("mkfifo");
return -1;
}
std::cout << "named pipe created at /tmp/myfifo" << std::endl;
return 0;
}
- 写入者进程
写入者进程向命名管道中写入数据。
writer.cpp:
#include
#include
#include
#include
int main() {
const char *fifo_path = "/tmp/myfifo";
const char *message = "hello from writer process!\n";
// 打开管道文件(写模式)
int fd = open(fifo_path, o_wronly);
if (fd == -1) {
perror("open");
return -1;
}
// 向管道写入数据
if (write(fd, message, strlen(message)) == -1) {
perror("write");
close(fd);
return -1;
}
std::cout << "message sent: " << message << std::endl;
// 关闭管道文件描述符
close(fd);
return 0;
}
- 读取者进程
读取者进程从命名管道中读取数据。
reader.cpp
#include
#include
#include
#include
int main() {
const char *fifo_path = "/tmp/myfifo";
char buffer[128];
// 打开管道文件(读模式)
int fd = open(fifo_path, o_rdonly);
if (fd == -1) {
perror("open");
return -1;
}
// 从管道读取数据
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read == -1) {
perror("read");
close(fd);
return -1;
}
buffer[bytes_read] = '\0'; // 确保字符串以 null 结尾
std::cout << "message received: " << buffer << std::endl;
// 关闭管道文件描述符
close(fd);
return 0;
}
编译与运行
1. 创建管道:
如果没有提前创建管道,运行 writer 时会阻塞,直到管道被创建。
可以手动创建管道:bash复制
mkfifo /tmp/myfifo
或者运行创建管道的程序。
- 编译代码:
将 writer.cpp 和 reader.cpp 分别保存为文件。
使用以下命令编译:bash复制
g -o writer writer.cpp
g -o reader reader.cpp
- 运行程序:
在一个终端运行读取者程序:
./reader
在另一个终端运行写入者程序:
./writer
输出示例
reader终端:message received: hello from writer process!
writer终端:message sent: hello from writer process!
注意事项
- 阻塞特性:
- 默认情况下,读取者会阻塞,直到有数据可读。
- 写入者会阻塞,直到有读取者打开管道。
- 如果不希望阻塞,可以在 open() 时使用 o_nonblock 标志。
- 管道文件路径:
- 确保管道文件路径一致(这里是 /tmp/myfifo)。
- 如果路径不存在,写入者会阻塞,直到管道被创建。
- 清理:
- 使用完管道后,可以手动删除管道文件:bash复制
rm /tmp/myfifo
- 跨进程通信:
- 命名管道允许不相关的进程之间通信,因此读取者和写入者可以是完全独立的程序。
通过这个示例,你可以看到命名管道如何实现进程间通信,非常适合需要跨进程传递数据的场景。
信号量
信号量(semaphore)是一种用于进程间或线程间同步的机制,用于控制对共享资源的访问。它通过维护一个计数器来实现同步,当计数器大于零时,表示资源可用;当计数器为零时,表示资源已被占用。信号量通常用于解决互斥(mutex)和同步(sync)问题。
以下是信号量的基本操作:
- p操作(wait/down/decrease):将信号量的值减1。如果减1后信号量的值小于0,则调用进程或线程阻塞,等待信号量的值变为非负。
-
v操作(signal/up/increase):将信号量的值加1。如果加1后信号量的值大于0,则唤醒一个等待该信号量的进程或线程。
- 信号量的分类
信号量主要分为两种:
- 二进制信号量(binary semaphore):值只能为0或1,用于互斥访问。
- 计数信号量(counting semaphore):值可以是任意非负整数,用于控制多个资源的访问。
- 信号量的实现
在c 中,信号量可以通过多种方式实现,包括系统v ipc信号量、posix信号量、boost库以及c 20标准中的std::semaphore。
2.1 系统v信号量
系统v信号量是基于ipc机制的信号量实现,使用semget、semop等函数。
2.2 posix信号量
posix信号量是另一种实现方式,使用sem_open、sem_wait和sem_post等函数。
2.3 boost信号量
boost库提供了跨平台的信号量实现,使用boost::interprocess::named_semaphore。
2.4 c 20 std::semaphore
c 20标准引入了std::semaphore,使得信号量的使用更加简洁。
- 信号量的使用场景
信号量主要用于以下场景:
- 互斥(mutex):确保多个线程或进程不会同时访问共享资源。
- 同步(sync):协调线程或进程的执行顺序,例如生产者-消费者问题。
- 注意事项
– 死锁:如果信号量的使用不当,可能会导致死锁。例如,多个线程或进程同时等待同一个信号量。
– 资源泄漏:在使用系统v或posix信号量时,需要确保信号量在程序结束时被正确删除,否则可能会导致资源泄漏。
– 性能:信号量的使用会引入上下文切换的开销,因此需要合理设计同步机制。
总结
信号量是一种强大的同步机制,适用于多种并发场景。根据具体需求,可以选择系统v信号量、posix信号量、boost信号量或c 20标准中的std::semaphore。
消息队列demo
在c 中,消息队列是一种常见的进程间通信(ipc)机制,允许不同进程之间以异步方式交换消息。以下是关于c 消息队列的实现和使用方法的总结:
-
系统v消息队列
系统v消息队列是一种传统的ipc机制,基于msgget、msgsnd和msgrcv等函数。 -
posix消息队列
posix消息队列提供了另一种实现方式,使用mq_open、mq_send和mq_receive等函数。 -
boost.interprocess消息队列
boost库提供了跨平台的消息队列实现,基于共享内存。 -
自定义线程安全消息队列
如果需要在多线程环境中使用消息队列,可以结合std::queue、std::mutex和std::condition_variable实现线程安全的消息队列。
总结
- 系统v和posix消息队列适用于进程间通信,但需要处理ipc资源的创建和销毁。
- boost.interprocess提供了跨平台的实现,基于共享内存。
- 自定义线程安全消息队列适用于多线程环境。
- 根据具体需求选择合适的消息队列实现方式。