简介
- 实现一个用户可以自定义缓冲区大小的管道
- 管道可以根据缓冲区的数据长度对用户的读和写操作进行合理的处理
- 只有写端注册时,会等到读端打开时写端注册才会返回
- 缓冲区没有数据时,读端会阻塞只到条件满足
- 缓冲区写不进完整的数据时,写端也会阻塞只到条件满足
代码
mypipe.h
#ifndef MYPIPE_H__
#define MYPIPE_H__
#define PIPE_READ 0x00000001UL
#define PIPE_WRITE 0x00000002UL
typedef void Mypipe_t;
int mypipe_init(Mypipe_t **pipe, int pipe_size);
int mypipe_register(Mypipe_t *pipe, u_int32_t opmap);
int mypipe_unregister(Mypipe_t *pipe, u_int32_t opmap);
int mypipe_read(Mypipe_t *pipe, void *res, size_t size);
int mypipe_write(Mypipe_t *pipe, void *data, size_t size);
int mypipe_destroy(Mypipe_t *pipe);
#endif
mypipe.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "./mypipe.h"
typedef struct mypipe_st{
char *data;
int pipesize;
int head;
int tail;
int datasize;
int count_read;
int count_write;
pthread_mutex_t mutex;
pthread_cond_t cond;
}mypipe_t;
int mypipe_init(Mypipe_t **pipe, int pipe_size){
mypipe_t *me = NULL;
me = (mypipe_t*)malloc(sizeof(*me));
if(me == NULL){
return -1;
}
me->pipesize = pipe_size;
me->data = (char*)malloc(me->pipesize);
if(me->data == NULL){
return -1;
}
pthread_mutex_init(&me->mutex, NULL);
pthread_cond_init(&me->cond, NULL);
#if 0
pthread_mutex_t blank_mtx = PTHREAD_MUTEX_INITIALIZER;
memcpy(&me->mutex, &blank_mtx, sizeof(blank_mtx));
pthread_cond_t blank_cnd = PTHREAD_COND_INITIALIZER;
memcpy(&me->cond, &blank_cnd, sizeof(blank_cnd));
#endif
me->head = 0;
me->tail = 0;
me->count_read = 0;
me->count_write = 0;
me->datasize = 0;
*pipe = me;
return 0;
}
int mypipe_register(Mypipe_t *pipe, u_int32_t opmap){
mypipe_t *me = pipe;
pthread_mutex_lock(&me->mutex);
if(opmap & PIPE_READ){
me->count_read++;
}
if(opmap & PIPE_WRITE){
me->count_write++;
}
pthread_cond_broadcast(&me->cond);
while(me->count_read <= 0 || me->count_write <= 0){
pthread_cond_wait(&me->cond, &me->mutex);
}
pthread_mutex_unlock(&me->mutex);
return 0;
}
int mypipe_unregister(Mypipe_t *pipe, u_int32_t opmap){
mypipe_t *me = pipe;
pthread_mutex_lock(&me->mutex);
if(opmap & PIPE_READ){
me->count_read--;
}
if(opmap & PIPE_WRITE){
me->count_write--;
}
pthread_cond_broadcast(&me->cond);
pthread_mutex_unlock(&me->mutex);
return 0;
}
static int get_next_idx(int idx, int max){
return (idx + 1) % max;
}
static int mypipe_readbyte(mypipe_t *me, char *res){
if(me->datasize <= 0){
return -1;
}
*res = me->data[me->head];
me->head = get_next_idx(me->head, me->pipesize);
me->datasize--;
return 0;
}
int mypipe_read(Mypipe_t *pipe, void *res, size_t size){
mypipe_t *me = pipe;
int i = 0;
pthread_mutex_lock(&me->mutex);
while(me->datasize <= 0 && me->count_write > 0){
pthread_cond_wait(&me->cond, &me->mutex);
}
if(me->datasize <= 0 && me->count_write <= 0){
pthread_mutex_unlock(&me->mutex);
return 0;
}
for(i = 0; i < size; i++){
if(mypipe_readbyte(me, res + i) != 0){
break;
}
}
pthread_cond_broadcast(&me->cond);
pthread_mutex_unlock(&me->mutex);
return i;
}
int mypipe_write(Mypipe_t *pipe, void *data, size_t size){
mypipe_t *me = pipe;
char *data_ = data;
int i = 0;
pthread_mutex_lock(&me->mutex);
while(me->datasize + size > me->pipesize && me->count_read > 0){
pthread_cond_wait(&me->cond, &me->mutex);
}
if(me->datasize + size > me->pipesize && me->count_read <= 0){
pthread_mutex_unlock(&me->mutex);
return -1;
}
while(i < size){
me->data[me->tail] = data_[i];
me->tail = get_next_idx(me->tail, me->pipesize);
me->datasize++;
i++;
}
pthread_cond_broadcast(&me->cond);
pthread_mutex_unlock(&me->mutex);
return 0;
}
int mypipe_destroy(Mypipe_t *pipe){
mypipe_t *me = pipe;
free(me->data);
pthread_mutex_destroy(&me->mutex);
pthread_cond_destroy(&me->cond);
free(me);
pipe = NULL;
return 0;
}
test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "./mypipe.h"
static void *my_func(void *arg){
Mypipe_t *me = arg;
puts("[read] register start.");
mypipe_register(me, PIPE_READ);
puts("[read] register finish.");
char msg[1024];
int len;
u_int64_t count_ = 0;
while(1){
len = mypipe_read(me, msg, 10);
count_ += len;
if(len == 0){
break;
}
write(1, msg, len);
fflush(stdout);
}
printf("total read %ld\n", count_);
pthread_exit(NULL);
}
int main(){
Mypipe_t *mypipe = NULL;
int pipe_size = 1024;
int ret = 0;
ret = mypipe_init(&mypipe, pipe_size);
if(ret){
fprintf(stderr, "mypipe error\n");
exit(1);
}
pthread_t tid;
pthread_create(&tid, NULL, my_func, mypipe);
pthread_create(&tid, NULL, my_func, mypipe);
pthread_create(&tid, NULL, my_func, mypipe);
puts("[write] register start.");
mypipe_register(mypipe, PIPE_WRITE);
puts("[write] register finish.");
int i;
u_int64_t count_ = 0;
for(i = 0; i < 1024 * 1024; i++){
ret = mypipe_write(mypipe, "saika-->saika\n", 15);
count_ += 15;
if(ret){
puts("write error");
}else{
puts("write ok");
}
}
puts("[write] unregister start.");
mypipe_unregister(mypipe, PIPE_WRITE);
puts("[write] unregister finish.");
pthread_join(tid, NULL);
printf("total write %ld\n", count_);
mypipe_destroy(mypipe);
exit(0);
}
测试截图

总结
实现功能
- 管道初始化以及销毁
- 身份注册,读者、写者统计
- 往管道里写
- 从管道里读
待实现功能
- 权限管理,可以在此代码上再封装一层,记录注册的身份信息,对读和写的操作进行权限管理,封装可以做成 open() 、close() 函数那样,同时引入 fd 类似的模式。