linux c语言 多线程之间使用管道进行通讯fifo 和参考kfifo实现的ring_buffer

linux 多进程通讯

clpsz/linux-ipcs: Linux进程间通信(Inter-Process Communication)方式汇总 (github.com) 

无名管道 pipe

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXLINE 256

int main(void)
{
    int n;
    int fd[2];
    pid_t pid;
    char line[MAXLINE];

    if (pipe(fd) < 0)
    {
        debug_error("pipe error");
        exit(-1);
    }
    if ((pid = fork()) < 0) 
    {
        debug_error("fork error");
        exit(-1);
    } 
    else if (pid > 0) 
    { /* parent */
        close(fd[0]);
        write(fd[1], "hello pipe\n", 12);
    }
    else { /* child */
        close(fd[1]);
        n = read(fd[0], line, MAXLINE);
        write(STDOUT_FILENO, line, n);
    }

    exit(0);
}

 

 

message

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/msg.h>



#define MSGKEY 1

typedef struct
{
    long type;
    //int type;//
    char buf[512];
} MSGBUF;


void parent()
{
    int msgid;
    int ret;
    MSGBUF msg;

    msgid = msgget(MSGKEY, IPC_CREAT| IPC_EXCL | 0666);
    if (msgid < 0)
    {
        perror("msgget: ");
        msgid = msgget(MSGKEY, 0666);
        goto remove;
    }
    usleep(100); // wait child entering receiving status

    msg.type = 10;//the type can't be 0,should >0;
    strcpy(msg.buf, "I am parent");

    ret = msgsnd(msgid, &msg, sizeof(msg.buf), IPC_NOWAIT); 
    if (ret < 0)
    {
        perror("msgsnd: ");
        goto remove;
    }

remove:
    ret = msgctl(msgid, IPC_RMID, NULL);
    if (ret < 0)
    {
        perror("msgctl: ");
    }
}

void child()
{
    int msgid;
    int ret;
    MSGBUF msg;

    msgid = msgget(MSGKEY, 0666);
    if (msgid < 0)
    {
        perror("msgget: ");
    }

    ret = msgrcv(msgid, &msg, sizeof(msg.buf), 10, 0);
    if (ret < 0)
    {
        perror("msgrcv: ");
        return;
    }
    printf("msg is: %s\n", msg.buf);
}

int main(void)
{
    pid_t pid;
    int status;

    if ((pid = fork()) < 0) 
    {
        debug_error("fork error");
        exit(-1);
    } 
    else if (pid > 0) 
    { /* parent */
        parent();
        wait(&status);
    }
    else
    { /* child */
        child();
    }

    exit(0);
}

 

 

 

 

有名管道fifo参考  (129条消息) linux c 使用fifo管道进行多线程间通信_土豆西瓜大芝麻的博客-CSDN博客_多线程fifo

完善后,字符串分割版本测试如下

测试fifo和pipe的程序如下

发送100MB数据进行测试 半双工

 

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#define msleep(m) usleep(m*1000)
#define max_send 64*1024*100   // MB

#define USING_PIPE 1

//编译    aarch64-linux-gnu-gcc -o t03_testfifo t03_testfifo.c -lpthread
 
/**
author:RYS
time:20220813
info:测试linuxfifo管道使用相关信息,使用案例demo,字符串分割填充和数据移动
*/ 
char *BUFFER = "0123456789ABCDE"; //加上\0一共16个字符 
int recivetotal,recivetotalstr,strtotal,sendtotal;
int reciveflag;


int fdwrite;
int fdread;
void *thread_fun_write(void *p)
{
    while(1)
    {
        sendtotal = max_send*(strlen(BUFFER)+1);
        printf("lastrecivetotal:%d \t lastrecivetotalstr:%d \t sendtotal:%d \t sendtotalstr:%d\tsend begin!!!\n",recivetotal,recivetotalstr,sendtotal,max_send);
        recivetotal=0;
        recivetotalstr=0;
        reciveflag=0;
        for(int i=0;i<max_send;i++){
            char* pos = BUFFER;
            int sendlen;
            int leastlen = strlen(BUFFER)+1;
            sendlen = write( fdwrite, pos,leastlen);
            while(sendlen<leastlen){
                printf("write fifo full\n");
                leastlen = leastlen - sendlen;
                pos += sendlen;
                sendlen = write( fdwrite, pos,leastlen);
            }
        }
        printf("write ok\n");
        msleep(1000);
    }
    close(fdwrite);
    return NULL;

}
void *thread_fun_read(void *p)
{
    
    int BUF_MAX = 1024;
    char buf[1024] = {0};
    int num;//保存读取数据的大小
    char* pos=buf;//记录位置
    char* packbegin;
    int leastlen = 0;
    
    unsigned int __test = 0;
    
    while(1)
    {
        num = read( fdread, pos, BUF_MAX-leastlen);
        if(num>0) {
            recivetotal += num;
            if(reciveflag==0){    
                reciveflag=1;
                printf("recive begin, first recive num:%d\n",num);
            } 
        }
        else {
            strtotal=0;__test++;if(__test%50000==0){printf(".");fflush(stdout);}
            continue;
        }//使用sleep重新启动起来太慢了
        num += pos-buf;
        pos = buf;
        packbegin = buf;
        
        while((pos-buf)<num){
            if(*pos!='\0'){pos++;continue;}

            //获取到一个串儿,调用函数进行处理
            if(strcmp(packbegin,BUFFER)!=0){ printf("recive strcmp error buf:%s____\n",packbegin); }
            strtotal++;
            
            
            pos++;
            packbegin=pos;
        }

        
        if(packbegin<pos){
            leastlen = pos-packbegin;
            memcpy(buf,packbegin,leastlen);
            *(buf+leastlen)='\0';
            pos = buf+leastlen;
            
            
            //printf("recive least num:%d  buf:%s____\n",leastlen,buf);
        }
        else{
            leastlen=0;
            pos = buf;
            
            
            //printf("recive parse finished, init param\t\tstrtotal:%d\n",strtotal);
            recivetotalstr += strtotal;strtotal=0;
            if(recivetotalstr>=max_send){
                printf("recive finished, recive strnum:%d\n",recivetotalstr);
            }
        }
        
    }
    close(fdread);
    return NULL; 
    
}
int main()
{
    printf("test v1.0.6 \n");
    
#if USING_PIPE
    printf("test pipe v1.0.6 \n");
    int fd[2];
    if (pipe(fd) < 0)
    {
        printf("pipe error\n");
        exit(-1);
    }
    fdread = fd[0];
    fdwrite = fd[1];
    
    if(fcntl(fdwrite,F_SETFL,FNDELAY) < 0){ //非阻塞,覆盖前面open的属性   
        printf("fcntl failed\n");   
    }
    if(fcntl(fdread,F_SETFL,FNDELAY) < 0){ //非阻塞,覆盖前面open的属性   
        printf("fcntl failed\n");   
    }
#else    
    printf("test fifo v1.0.6 \n");
    //创建有名管道,如果管道存在则直接使用
    int n = mkfifo("./myfifo",0664);
    if( n < 0 && errno!=EEXIST)
    {
        perror("mkfifo");
        return -1;
    }
    

    fdread = open("./myfifo", O_RDONLY|O_NONBLOCK );//非阻塞
    if(fdread == -1)
    {
        printf("read fifo open fail...\n");            
        return -1;
    }
    
    fdwrite = open("./myfifo",O_WRONLY);//非阻塞
    if(fdwrite == -1)
    {
        printf("write fifo open fail....\n");
        return -1;
    }

    if(fcntl(fdwrite,F_SETFL,FNDELAY) < 0){ //非阻塞,覆盖前面open的属性   
        printf("fcntl failed\n");   
    }
#endif
    
    //创建线程
    pthread_t writeId,readId;
    pthread_create( &writeId, NULL, thread_fun_write, NULL );
    pthread_create( &readId, NULL, thread_fun_read, NULL);
 
    pthread_join(writeId,NULL);
    pthread_join(readId,NULL);
    while(1);
    return 0;
}

 

 

 //

kfifo

Linux内核结构体--kfifo 环状缓冲区 - 知乎 (zhihu.com)

 

浅谈Linux内核无锁编程原理 - 知乎 (zhihu.com)

 

(129条消息) linux内核之无锁缓冲队列kfifo原理(结合项目实践)_不如吃个药的博客-CSDN博客_kfifo

 

(129条消息) Linux内核结构体--kfifo 环状缓冲区_鱼思故渊的博客-CSDN博客

 

/**@brief 仿照linux kfifo写的ring buffer
 *@atuher Anker  date:2013-12-18
* ring_buffer.h
 * */
 
#ifndef KFIFO_HEADER_H 
#define KFIFO_HEADER_H
 
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
 
//判断x是否是2的次方
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
//取a和b中最小值
#define min(a, b) (((a) < (b)) ? (a) : (b))
 
struct ring_buffer
{
    void         *buffer;     //缓冲区
    uint32_t     size;       //大小
    uint32_t     in;         //入口位置
    uint32_t       out;        //出口位置
    pthread_mutex_t *f_lock;    //互斥锁
};
//初始化缓冲区
struct ring_buffer* ring_buffer_init(void *buffer, uint32_t size, pthread_mutex_t *f_lock)
{
    assert(buffer);
    struct ring_buffer *ring_buf = NULL;
    if (!is_power_of_2(size))
    {
    fprintf(stderr,"size must be power of 2.\n");
        return ring_buf;
    }
    ring_buf = (struct ring_buffer *)malloc(sizeof(struct ring_buffer));
    if (!ring_buf)
    {
        fprintf(stderr,"Failed to malloc memory,errno:%u,reason:%s",
            errno, strerror(errno));
        return ring_buf;
    }
    memset(ring_buf, 0, sizeof(struct ring_buffer));
    ring_buf->buffer = buffer;
    ring_buf->size = size;
    ring_buf->in = 0;
    ring_buf->out = 0;
        ring_buf->f_lock = f_lock;
    return ring_buf;
}
//释放缓冲区
void ring_buffer_free(struct ring_buffer *ring_buf)
{
    if (ring_buf)
    {
    if (ring_buf->buffer)
    {
        free(ring_buf->buffer);
        ring_buf->buffer = NULL;
    }
    free(ring_buf);
    ring_buf = NULL;
    }
}
 
//缓冲区的长度
uint32_t __ring_buffer_len(const struct ring_buffer *ring_buf)
{
    return (ring_buf->in - ring_buf->out);
}
 
//从缓冲区中取数据
uint32_t __ring_buffer_get(struct ring_buffer *ring_buf, void * buffer, uint32_t size)
{
    assert(ring_buf || buffer);
    uint32_t len = 0;
    size  = min(size, ring_buf->in - ring_buf->out);        
    /* first get the data from fifo->out until the end of the buffer */
    len = min(size, ring_buf->size - (ring_buf->out & (ring_buf->size - 1)));
    memcpy(buffer, ring_buf->buffer + (ring_buf->out & (ring_buf->size - 1)), len);
    /* then get the rest (if any) from the beginning of the buffer */
    memcpy(buffer + len, ring_buf->buffer, size - len);
    ring_buf->out += size;
    return size;
}
//向缓冲区中存放数据
uint32_t __ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)
{
    assert(ring_buf || buffer);
    uint32_t len = 0;
    size = min(size, ring_buf->size - ring_buf->in + ring_buf->out);
    /* first put the data starting from fifo->in to buffer end */
    len  = min(size, ring_buf->size - (ring_buf->in & (ring_buf->size - 1)));
    memcpy(ring_buf->buffer + (ring_buf->in & (ring_buf->size - 1)), buffer, len);
    /* then put the rest (if any) at the beginning of the buffer */
    memcpy(ring_buf->buffer, buffer + len, size - len);
    ring_buf->in += size;
    return size;
}
 
uint32_t ring_buffer_len(const struct ring_buffer *ring_buf)
{
    uint32_t len = 0;
    pthread_mutex_lock(ring_buf->f_lock);
    len = __ring_buffer_len(ring_buf);
    pthread_mutex_unlock(ring_buf->f_lock);
    return len;
}
 
uint32_t ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, uint32_t size)
{
    uint32_t ret;
    pthread_mutex_lock(ring_buf->f_lock);
    ret = __ring_buffer_get(ring_buf, buffer, size);
    //buffer中没有数据
    if (ring_buf->in == ring_buf->out)
    ring_buf->in = ring_buf->out = 0;
    pthread_mutex_unlock(ring_buf->f_lock);
    return ret;
}
 
uint32_t ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)
{
    uint32_t ret;
    pthread_mutex_lock(ring_buf->f_lock);
    ret = __ring_buffer_put(ring_buf, buffer, size);
    pthread_mutex_unlock(ring_buf->f_lock);
    return ret;
}
#endif

 

 

//测试代码

/**@brief ring buffer测试程序,创建两个线程,一个生产者,一个消费者。
 * 生产者每隔1秒向buffer中投入数据,消费者每隔2秒去取数据。
 *@atuher Anker  date:2013-12-18
 * */
#include "ring_buffer.h"
#include <pthread.h>
#include <time.h>
 
#define BUFFER_SIZE  1024 * 1024
 
typedef struct student_info
{
    uint64_t stu_id;
    uint32_t age;
    uint32_t score;
}student_info;
 
 
void print_student_info(const student_info *stu_info)
{
    assert(stu_info);
    printf("id:%lu\t",stu_info->stu_id);
    printf("age:%u\t",stu_info->age);
    printf("score:%u\n",stu_info->score);
}
 
student_info * get_student_info(time_t timer)
{
    student_info *stu_info = (student_info *)malloc(sizeof(student_info));
    if (!stu_info)
    {
    fprintf(stderr, "Failed to malloc memory.\n");
    return NULL;
    }
    srand(timer);
    stu_info->stu_id = 10000 + rand() % 9999;
    stu_info->age = rand() % 30;
    stu_info->score = rand() % 101;
    print_student_info(stu_info);
    return stu_info;
}
 
void * consumer_proc(void *arg)
{
    struct ring_buffer *ring_buf = (struct ring_buffer *)arg;
    student_info stu_info; 
    while(1)
    {
    sleep(2);
    printf("------------------------------------------\n");
    printf("get a student info from ring buffer.\n");
    ring_buffer_get(ring_buf, (void *)&stu_info, sizeof(student_info));
    printf("ring buffer length: %u\n", ring_buffer_len(ring_buf));
    print_student_info(&stu_info);
    printf("------------------------------------------\n");
    }
    return (void *)ring_buf;
}
 
void * producer_proc(void *arg)
{
    time_t cur_time;
    struct ring_buffer *ring_buf = (struct ring_buffer *)arg;
    while(1)
    {
    time(&cur_time);
    srand(cur_time);
    int seed = rand() % 11111;
    printf("******************************************\n");
    student_info *stu_info = get_student_info(cur_time + seed);
    printf("put a student info to ring buffer.\n");
    ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));
    printf("ring buffer length: %u\n", ring_buffer_len(ring_buf));
    printf("******************************************\n");
    sleep(1);
    }
    return (void *)ring_buf;
}
 
int consumer_thread(void *arg)
{
    int err;
    pthread_t tid;
    err = pthread_create(&tid, NULL, consumer_proc, arg);
    if (err != 0)
    {
    fprintf(stderr, "Failed to create consumer thread.errno:%u, reason:%s\n",
        errno, strerror(errno));
    return -1;
    }
    return tid;
}
int producer_thread(void *arg)
{
    int err;
    pthread_t tid;
    err = pthread_create(&tid, NULL, producer_proc, arg);
    if (err != 0)
    {
    fprintf(stderr, "Failed to create consumer thread.errno:%u, reason:%s\n",
        errno, strerror(errno));
    return -1;
    }
    return tid;
}
 
 
int main()
{
    void * buffer = NULL;
    uint32_t size = 0;
    struct ring_buffer *ring_buf = NULL;
    pthread_t consume_pid, produce_pid;
 
    pthread_mutex_t *f_lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
    if (pthread_mutex_init(f_lock, NULL) != 0)
    {
    fprintf(stderr, "Failed init mutex,errno:%u,reason:%s\n",
        errno, strerror(errno));
    return -1;
    }
    buffer = (void *)malloc(BUFFER_SIZE);
    if (!buffer)
    {
    fprintf(stderr, "Failed to malloc memory.\n");
    return -1;
    }
    size = BUFFER_SIZE;
    ring_buf = ring_buffer_init(buffer, size, f_lock);
    if (!ring_buf)
    {
    fprintf(stderr, "Failed to init ring buffer.\n");
    return -1;
    }
#if 0
    student_info *stu_info = get_student_info(638946124);
    ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));
    stu_info = get_student_info(976686464);
    ring_buffer_put(ring_buf, (void *)stu_info, sizeof(student_info));
    ring_buffer_get(ring_buf, (void *)stu_info, sizeof(student_info));
    print_student_info(stu_info);
#endif
    printf("multi thread test.......\n");
    produce_pid  = producer_thread((void*)ring_buf);
    consume_pid  = consumer_thread((void*)ring_buf);
    //pthread_join(produce_pid, NULL);
    //pthread_join(consume_pid, NULL);
while(1){sleep(10);} ring_buffer_free(ring_buf);
free(f_lock); return 0; }

 

 

 

 

 

//

posted @ 2022-08-12 15:54  小城熊儿  阅读(904)  评论(0编辑  收藏  举报