epoll简单示例

通过经典的client-server模型演示一下epoll监听pipe的用法。模型如下图。

首先创建用于通信的命名管道,三个producer-client管道,一个client-server管道。

int cp[N_THREAD];	//client-producer-pipe描述符
//创建并打开client-producer-pipe
for(int i = 0; i < N_THREAD; ++i)
{
	char path[128] = {0};
	sprintf(path, "%s%d", PRODUCER_CLIENT, i);
	mkfifo(path, 0666);
	cp[i] = open(path, O_RDWR);
}

//创建并打开client-server-pipe
mkfifo(CLIENT_SERVER, 0666);
int cs = open(CLIENT_SERVER, O_WRONLY);

创建producer子线程。

void* producer(void *arg)
{
	int id = *((int*)arg);
	char buf[DATA_SIZE] = {0};
	while(1){		
		sleep(rand() % 3 + 1);	
		int data = rand() % 1000;
		sprintf(buf, "%d", data);
		write(cp[id], buf, sizeof(buf));
		printf("id:%d data:%d\n", id, data);
		memset(buf, 0, sizeof(buf));
	}
}
//创建生产者子线程
pthread_t tid[N_THREAD];
int id[N_THREAD];	//线程标识
for(int i = 0; i < N_THREAD; ++i)
{
	id[i] = i;
	pthread_create(&tid[i], NULL, producer, id + i);
}

创建epoll,注册监听事件。注册监听事件分为三部,设置监听事件标识符,设置事件触发条件,注册设置好的事件。

//创建epoll	
int epfd = epoll_create(N_THREAD + 1);
struct epoll_event event[N_THREAD + 1];
for(int i = 0; i < N_THREAD; ++i)
{	
	event[i].data.fd = cp[i];
	event[i].events = EPOLLIN;	
	epoll_ctl(epfd, EPOLL_CTL_ADD, cp[i], event + i);
}
event[N_THREAD].data.fd = cs;
event[N_THREAD].events = EPOLLOUT;	
epoll_ctl(epfd, EPOLL_CTL_ADD, cs, event + N_THREAD);

监听epoll。epoll_wait监听到事件相关信息会记录到wait_event中,可根据监听到的标识符选择不同的应对方式,返回值为监听到的事件个数。

//监听epoll
struct epoll_event wait_event[N_THREAD + 1];
char buf[DATA_SIZE] = {0};
while(1){
	int n = epoll_wait(epfd, wait_event, N_THREAD + 1, -1);
	for(int i = 0; i < n; ++i)
	{
		if(wait_event[i].data.fd == cs)
		{
			if(!isEmpty(&buffer))
			{
				int data;
				pop(&buffer, &data);
				memset(buf, 0, sizeof(buf));
				sprintf(buf, "%d", data);
				write(cs, buf, sizeof(buf));
			}
		}
		else
		{	
			memset(buf, 0, sizeof(buf));
			read(wait_event[i].data.fd, buf, sizeof(buf));
			if(!isFull(&buffer)){
				int data;
				sscanf(buf, "%d", &data);
				push(&buffer, data);
			}
		}
	}
}

server部分与client部分类似。下面放出完整代码。

//client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <sys/syscall.h>

#define PRODUCER_CLIENT "./producer_client"
#define CLIENT_SERVER "./client_server"
#define N_THREAD 3	//线程数
#define DATA_SIZE 5	//数据大小
#define BUFFER_SIZE 20//缓冲区大小

//定义缓冲区
typedef struct Queue{
    int rear;
    int front;
    int elem[BUFFER_SIZE];
}Queue;
void initQueue(Queue*);
int push(Queue*, int);
int pop(Queue*, int*);
int isEmpty(Queue*);
int isFull(Queue*);

void* producer(void*);

int cp[N_THREAD];	//client-producer-pipe描述符

int main(int argc, char *argv[])
{
	Queue buffer;
	initQueue(&buffer);

	//创建并打开client-producer-pipe
	for(int i = 0; i < N_THREAD; ++i)
	{
		char path[128] = {0};
		sprintf(path, "%s%d", PRODUCER_CLIENT, i);
		mkfifo(path, 0666);
		cp[i] = open(path, O_RDWR);
	}
	
	//创建并打开client-server-pipe
	mkfifo(CLIENT_SERVER, 0666);
	int cs = open(CLIENT_SERVER, O_WRONLY);

	//创建生产者子线程
	pthread_t tid[N_THREAD];
	int id[N_THREAD];	//线程标识
	for(int i = 0; i < N_THREAD; ++i)
	{
		id[i] = i;
		pthread_create(&tid[i], NULL, producer, id + i);
	}

	//创建epoll	
	int epfd = epoll_create(N_THREAD + 1);
	struct epoll_event event[N_THREAD + 1];
	for(int i = 0; i < N_THREAD; ++i)
	{	
		event[i].data.fd = cp[i];
		event[i].events = EPOLLIN;	
		epoll_ctl(epfd, EPOLL_CTL_ADD, cp[i], event + i);
	}
	event[N_THREAD].data.fd = cs;
	event[N_THREAD].events = EPOLLOUT;	
	epoll_ctl(epfd, EPOLL_CTL_ADD, cs, event + N_THREAD);

	//监听epoll
	struct epoll_event wait_event[N_THREAD + 1];
	char buf[DATA_SIZE] = {0};
	while(1){
		int n = epoll_wait(epfd, wait_event, N_THREAD + 1, -1);
		for(int i = 0; i < n; ++i)
		{
			if(wait_event[i].data.fd == cs)
			{
				if(!isEmpty(&buffer))
				{
					int data;
					pop(&buffer, &data);
					memset(buf, 0, sizeof(buf));
					sprintf(buf, "%d", data);
					write(cs, buf, sizeof(buf));
				}
			}
			else
			{	
				memset(buf, 0, sizeof(buf));
				read(wait_event[i].data.fd, buf, sizeof(buf));
				if(!isFull(&buffer)){
					int data;
					sscanf(buf, "%d", &data);
					push(&buffer, data);
				}
			}
		}
	}
	for(int i = 0; i < N_THREAD; ++i)
	{
		pthread_join(tid[i], NULL);
	}
	for(int i = 0; i < N_THREAD; ++i)
	{
		close(cp[i]);
	}
	close(cs);
	return 0;
}

void* producer(void *arg)
{
	int id = *((int*)arg);
	char buf[DATA_SIZE] = {0};
	while(1){		
		sleep(rand() % 3 + 1);	
		int data = rand() % 1000;
		sprintf(buf, "%d", data);
		write(cp[id], buf, sizeof(buf));
		printf("id:%d data:%d\n", id, data);
		memset(buf, 0, sizeof(buf));
	}
}

void initQueue(Queue* q)
{
	memset(q, 0, sizeof(Queue));
}

int push(Queue* q, int data)
{
	if(isFull(q))
		return 0;
	q->elem[q->rear] = data;
	q->rear = (q->rear + 1) % BUFFER_SIZE;
	return 1;
}

int pop(Queue* q, int* data)
{
	if(isEmpty(q))
		return 0;
	*data = q->elem[q->front];
	q->front = (q->front + 1) % BUFFER_SIZE;
	return 1;
}

int isEmpty(Queue* q)
{
	return q->rear == q->front;
}

int isFull(Queue* q)
{
	return (q->rear + 1) % BUFFER_SIZE == q->front;
}
//server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <sys/syscall.h>

#define SERVER_CONSUMER "./server_consumer"
#define CLIENT_SERVER "./client_server"
#define N_THREAD 3	//线程数
#define DATA_SIZE 5	//数据大小
#define BUFFER_SIZE 20	//缓冲区大小

//定义缓冲区
typedef struct Queue{
    int rear;
    int front;
    int elem[BUFFER_SIZE];
}Queue;
void initQueue(Queue*);
int push(Queue*, int);
int pop(Queue*, int*);
int isEmpty(Queue*);
int isFull(Queue*);

void* consumer(void*);

int fd[N_THREAD];	//server-consumer-pipe描述符

int main(int argc, char *argv[])
{	
	Queue buffer;
	initQueue(&buffer);
	
	//创建并打开server-consumer-pipe
	for(int i = 0; i < N_THREAD; ++i)
	{
		char path[128] = {0};
		sprintf(path, "%s%d", SERVER_CONSUMER, i);
		mkfifo(path, 0666);
		fd[i] = open(path, O_RDWR);
	}

	//打开client-server-pipe(由client创建)
	int cs = open(CLIENT_SERVER, O_RDONLY);

	//创建消费者子线程
	pthread_t tid[N_THREAD];
	int id[N_THREAD];	//线程标识
	for(int i = 0; i < N_THREAD; ++i)
	{
		id[i] = i;
		pthread_create(&tid[i], NULL, consumer, id + i);
	}
	
	//创建epoll
	int epfd = epoll_create(N_THREAD + 1);
	struct epoll_event event[N_THREAD + 1];
	for(int i = 0; i < N_THREAD; ++i)
	{	
		event[i].data.fd = fd[i];
		event[i].events = EPOLLOUT;	
		epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i], event + i);
	}
	event[N_THREAD].data.fd = cs;
	event[N_THREAD].events = EPOLLIN;	
	epoll_ctl(epfd, EPOLL_CTL_ADD, cs, event + N_THREAD);

	//监听epoll
	struct epoll_event wait_event[N_THREAD + 1];
	while(1){
		int n = epoll_wait(epfd, wait_event, N_THREAD + 1, -1);
		char buf[DATA_SIZE] = {0};
		for(int i = 0; i < n; ++i)
		{
			if(wait_event[i].data.fd == cs)
			{
				memset(buf, 0, sizeof(buf));
				read(cs, buf, sizeof(buf));
				if(!isFull(&buffer)){
					int data;
					sscanf(buf, "%d", &data);
					push(&buffer, data);
				}
			}
			else
			{
				if(!isEmpty(&buffer))
				{	
					int data;
					pop(&buffer, &data);
					memset(buf, 0, sizeof(buf));
					sprintf(buf, "%d", data);
					write(wait_event[i].data.fd, buf, sizeof(buf));
				}
			}
		}
		
	}
	for(int i = 0; i < N_THREAD; ++i)
	{
		pthread_join(tid[i], NULL);
	}
	for(int i = 0; i < N_THREAD; ++i)
	{
		close(fd[i]);
	}
	return 0;
}

void* consumer(void *arg)
{
	int id = *((int*)arg);
	
	char buf[DATA_SIZE] = {0};
	while(1){
		memset(buf, 0, sizeof(buf));		
		read(fd[id], buf, sizeof(buf));
		sleep(rand() % 3 + 1);
		int data;
		sscanf(buf, "%d", &data);
		printf("id:%d data:%d\n", id, data);				
	}
}

void initQueue(Queue* q)
{
	memset(q, 0, sizeof(Queue));
}

int push(Queue* q, int data)
{
	if(isFull(q))
		return 0;
	q->elem[q->rear] = data;
	q->rear = (q->rear + 1) % BUFFER_SIZE;
	return 1;
}

int pop(Queue* q, int* data)
{
	if(isEmpty(q))
		return 0;
	*data = q->elem[q->front];
	q->front = (q->front + 1) % BUFFER_SIZE;
	return 1;
}

int isEmpty(Queue* q)
{
	return q->rear == q->front;
}

int isFull(Queue* q)
{
	return (q->rear + 1) % BUFFER_SIZE == q->front;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值