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; }
//