自己实现多线程环境下的pipe

简介

  • 实现一个用户可以自定义缓冲区大小的管道
  • 管道可以根据缓冲区的数据长度对用户的读和写操作进行合理的处理
    - 只有写端注册时,会等到读端打开时写端注册才会返回
    - 缓冲区没有数据时,读端会阻塞只到条件满足
    - 缓冲区写不进完整的数据时,写端也会阻塞只到条件满足

代码

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);

// 注册身份, opmap 为位图,支持与操作
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;
        // printf("len = %d\n", 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);
}

测试截图

01

总结

实现功能

  1. 管道初始化以及销毁
  2. 身份注册,读者、写者统计
  3. 往管道里写
  4. 从管道里读

待实现功能

  1. 权限管理,可以在此代码上再封装一层,记录注册的身份信息,对读和写的操作进行权限管理,封装可以做成 open() 、close() 函数那样,同时引入 fd 类似的模式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值