沫颖 的学生作业:
代码
/**
* 1-11 多路复用 io-epoll(二) 控制与等待 - 课后练习
示例
等待用户输入数据,如果没有则打印 timeout,否则获取用户输入,并输出
练习
使用 epoll 监听有名管道,当有名管道有数据时,读取数据并打印
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 1024
#define TIMEOUT_MS 3000 // 超时时间(毫秒)
#define MESSAGE_PREFIX "Hello from fifo1-"
#define MAXEVENTS 10 // 事件监听数
// 子线程函数:读取 FIFO 数据
void *thread_function(void *arg) {
const char *fifo_name = (const char *)arg;
int fd, epfd;
// 打开有名管道
printf("Thread %lu: 打开 FIFO %s\n", pthread_self(), fifo_name);
fd = open(fifo_name, O_RDONLY);
if (fd == -1) {
perror("open");
pthread_exit(NULL);
}
epfd = epoll_create(1);
if (-1 == epfd) {
perror("epoll_create");
}
struct epoll_event ev;
struct epoll_event ret_ev[MAXEVENTS];
ev.data.fd = fd; // 监视有名管道的文件描述符
ev.events = EPOLLIN; // 监视可读事件
// 调用 epoll 添加监听事件
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
while (1) {
// 等待有名管道文件描述符关联的事件发生
ret = epoll_wait(epfd, ret_ev, MAXEVENTS, TIMEOUT_MS);
if (ret == -1) {
perror("poll");
break;
} else if (ret == 0) {
// 超时
printf("Time Out!\n");
} else {
// 检查有名管道是否可读
if (ret_ev->events & EPOLLIN) {
char buffer[BUFFER_SIZE];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("从 FIFO 读取到数据: %s", buffer);
} else if (bytes_read == 0) {
// EOF
printf("FIFO 已关闭\n");
} else {
perror("read");
}
}
}
}
close(fd);
pthread_exit(NULL);
}
int main() {
const char *fifo_name = "myfifo";
// 创建有名管道
if (mkfifo(fifo_name, 0666) == -1) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
pthread_t thread1;
// 创建线程(先启动子线程,确保读取端先打开)
printf("Main: 创建子线程\n");
if (pthread_create(&thread1, NULL, thread_function, (void *)fifo_name) != 0) {
perror("pthread_create");
unlink(fifo_name); // 删除有名管道
exit(EXIT_FAILURE);
}
// 等待子线程打开 FIFO 的读取端
sleep(1);
// 打开有名管道的写入端
printf("Main: 打开 FIFO %s\n", fifo_name);
int fd1 = open(fifo_name, O_WRONLY);
if (fd1 == -1) {
perror("open write end");
unlink(fifo_name); // 删除有名管道
exit(EXIT_FAILURE);
}
// 主线程写入数据到有名管道
int counter = 0;
while (1) {
char message1[BUFFER_SIZE];
// 拼接字符串
snprintf(message1, sizeof(message1), "%s%d\n", MESSAGE_PREFIX, counter++);
// 写入数据
if (write(fd1, message1, strlen(message1)) == -1) {
perror("write");
}
// 等待一段时间(确保大于超时时间)
sleep(TIMEOUT_MS / 1000 + 1); // 确保写入间隔大于超时时间
}
// 关闭写入端
printf("Main: 关闭 FIFO %s\n", fifo_name);
close(fd1);
// 等待线程结束
printf("Main: 等待子线程结束\n");
pthread_join(thread1, NULL);
// 删除有名管道
printf("Main: 删除 FIFO %s...\n", fifo_name);
unlink(fifo_name);
return 0;
}
结果
felix@felixlinux:~/Desktop/Study/CProjects/imooc-embedded/Stage05/Week12/Class12$ gcc demo_12_11.c
felix@felixlinux:~/Desktop/Study/CProjects/imooc-embedded/Stage05/Week12/Class12$ ./a.out
Main: 创建子线程
Thread 281473135341856: 打开 FIFO myfifo
Main: 打开 FIFO myfifo
从 FIFO 读取到数据: Hello from fifo1-0
Time Out!
从 FIFO 读取到数据: Hello from fifo1-1
Time Out!
从 FIFO 读取到数据: Hello from fifo1-2
Time Out!
从 FIFO 读取到数据: Hello from fifo1-3
Time Out!
ç从 FIFO 读取到数据: Hello from fifo1-4
^C