1. 协调多线程与匿名管道协作
- 避免竞争条件:
- 使用互斥锁(
pthread_mutex_t
)来保护对匿名管道的读写操作。在进行读或写操作前,先获取互斥锁,操作完成后释放互斥锁。
- 对于多线程读操作,可以使用条件变量(
pthread_cond_t
)来通知线程有数据可读,避免无效的读操作竞争。
- 避免死锁:
- 按照固定顺序获取锁。例如,如果有多个互斥锁,所有线程都以相同顺序获取这些锁,避免循环依赖导致死锁。
- 使用超时机制,在获取锁时设置一个超时时间,如果在规定时间内未能获取到锁,则放弃操作并进行相应处理。
2. 资源管理
- 文件描述符管理:
- 在父进程创建匿名管道后,将文件描述符传递给子线程。注意在子线程结束时,要正确关闭文件描述符,避免资源泄漏。
- 可以使用
fcntl
函数设置文件描述符为非阻塞模式,这样在读写操作时可以避免线程阻塞。
- 内存管理:
- 使用动态内存分配函数(如
malloc
、calloc
)分配内存时,要确保在不再使用时使用相应的释放函数(如free
)进行释放。
- 对于多线程共享的内存区域,要使用互斥锁等同步机制来保护内存的读写操作。
3. 代码框架及关键部分解释
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <string.h>
#define BUFFER_SIZE 1024
// 定义全局变量
int pipe_fds[2];
pthread_mutex_t pipe_mutex;
pthread_cond_t data_ready;
char buffer[BUFFER_SIZE];
// 线程函数,用于写管道
void* write_to_pipe(void* arg) {
// 加锁
pthread_mutex_lock(&pipe_mutex);
const char* message = "Hello from thread";
write(pipe_fds[1], message, strlen(message));
// 解锁并通知有数据可读
pthread_cond_signal(&data_ready);
pthread_mutex_unlock(&pipe_mutex);
return NULL;
}
// 线程函数,用于读管道
void* read_from_pipe(void* arg) {
// 加锁
pthread_mutex_lock(&pipe_mutex);
// 使用条件变量等待数据
while (read(pipe_fds[0], buffer, BUFFER_SIZE) == 0) {
pthread_cond_wait(&data_ready, &pipe_mutex);
}
printf("Read from pipe: %s\n", buffer);
// 解锁
pthread_mutex_unlock(&pipe_mutex);
return NULL;
}
int main() {
pthread_t write_thread, read_thread;
// 初始化互斥锁和条件变量
pthread_mutex_init(&pipe_mutex, NULL);
pthread_cond_init(&data_ready, NULL);
// 创建匿名管道
if (pipe(pipe_fds) == -1) {
perror("pipe");
return 1;
}
// 设置管道读端为非阻塞模式
int flags = fcntl(pipe_fds[0], F_GETFL, 0);
fcntl(pipe_fds[0], F_SETFL, flags | O_NONBLOCK);
// 创建写线程
if (pthread_create(&write_thread, NULL, write_to_pipe, NULL) != 0) {
perror("pthread_create write");
return 1;
}
// 创建读线程
if (pthread_create(&read_thread, NULL, read_from_pipe, NULL) != 0) {
perror("pthread_create read");
return 1;
}
// 等待线程结束
pthread_join(write_thread, NULL);
pthread_join(read_thread, NULL);
// 关闭管道文件描述符
close(pipe_fds[0]);
close(pipe_fds[1]);
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&pipe_mutex);
pthread_cond_destroy(&data_ready);
return 0;
}
- 关键部分解释:
- 互斥锁和条件变量初始化:在
main
函数中,使用pthread_mutex_init
初始化互斥锁pipe_mutex
,使用pthread_cond_init
初始化条件变量data_ready
。
- 匿名管道创建:使用
pipe
函数创建匿名管道,返回的文件描述符存储在pipe_fds
数组中,pipe_fds[0]
为读端,pipe_fds[1]
为写端。
- 设置非阻塞模式:通过
fcntl
函数将管道读端设置为非阻塞模式,避免读操作阻塞线程。
- 线程函数:
write_to_pipe
线程函数在获取互斥锁后向管道写端写入数据,然后通过条件变量通知有数据可读;read_from_pipe
线程函数在获取互斥锁后,使用条件变量等待数据,有数据时读取并打印。
- 资源清理:在
main
函数结束前,关闭管道文件描述符,销毁互斥锁和条件变量,确保资源正确释放。