使用pipe、select实现线程间通信和性能测试

news2024/12/23 6:53:16

一 代码实现

理论依据:

管道中无数据时,读阻塞。

写数据时,长度小于PIPE_BUF时,写数据是原子操作,这样不会出现写一半的情况。在我的虚拟机上PIPE_BUF的值是4096,在标准中linux系统中该值都是4096.

 测试代码:编写源码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>

#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)

struct mq_data{
    int len;
    int cmd;
    int seq;    
    char data[128];
};

//写线程
void *pthread_write(void *arg){
    int fd = (int)arg;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    data.len = sizeof("456");
    memcpy(data.data,"456",sizeof("456"));
    write(fd,&data,sizeof(data));
    return NULL;
}
//读线程
void *pthread_read(void *arg){
    int fd = (int)arg;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    int len = read(fd,&data,sizeof(data));
    DEBUG_INFO("read %d,data = %s",len,data.data);
    exit(0);
    return NULL;
}
int main(int argc, char *argv[])
{
    int res = 0;
    int fds[2];
    res = pipe(fds);
    if(res < 0){
        perror("pipe");
        return -1;
    }
    pthread_t p1,p2;
    res = pthread_create(&p1,NULL,pthread_write,(void*)fds[1]);
    if(res == -1){
        perror("pthread_create");
        return -1;
    }
    pthread_detach(p1);
    res = pthread_create(&p2,NULL,pthread_read,(void*)fds[0]);
    if(res == -1){
        perror("pthread_create");
        return -1;

    }
    pthread_detach(p2);

    while(1){
        sleep(1);
    }
    return 0;
}

CMakeLists

cmake_minimum_required(VERSION 3.8)
project(myapp)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pthread")
add_executable(pipe_thread_com pipe_thread_com.c)

 编译脚本

rm -rf _build_
mkdir _build_ -p
cmake -S ./ -B _build_
make -C _build_
./_build_/pipe_thread_com

测试结果:

二 time命令

time命令最常用的使用方式就是在其后面直接跟上命令和参数:

1

time [options]command [arguments...]

在命令执行完成之后就会打印出CPU的使用情况:

real 0m5.064s <== 实际使用时间(real time)

user 0m0.020s <== 用户态使用时间(the process spent in user mode)

sys 0m0.040s <== 内核态使用时间(the process spent in kernel mode)

time命令跟上-p参数可以只打印时间数值(秒数),不打印单位。

实例,这是测试sleep 1命令执行花费的时间,这不是废话吗,肯定是一秒啊?结果如下所示,结果是1.002秒。2毫秒有必要计较吗?当然有必要。

$ time sleep 1

real    0m1.002s
user    0m0.001s
sys     0m0.000s

 这个测试至少还说明了,sleep命令完全是在用户态实现的。

三 性能测试 

测试一 测试上面代码的花费时间,总计1毫秒,系统调用时间为0.应该是太短忽略不计了吧。

$ time ./pipe_thread_com 
/big/work/ipc/pipe_thread_com.c - 33 - pthread_read :: read 140,data = 456

real    0m0.001s
user    0m0.001s
sys     0m0.000s

修改代码,写1000次,在读线程中读1000次,然后使用time观察时间。发现时间和一次一样。

嗯,修改测试次数为10万次。

下面是优化后的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>

#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)

#define TEST_MAX_COUNT 100000
struct mq_data{
    int len;
    int cmd;
    int seq;    
    char data[128];
};

//写线程
void *pthread_write(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    data.len = sizeof("456");
    memcpy(data.data,"456",sizeof("456"));
    for(int i=0; i<TEST_MAX_COUNT;i++){
       res = write(fd,&data,sizeof(data));
       if(res < 0){
        DEBUG_INFO("write:");
        break;
       }
    }
    close(fd);
    return NULL;
}
//读线程
void *pthread_read(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    int count = 0;
    do{
        res = read(fd,&data,sizeof(data));
        if(res == 0){
            DEBUG_INFO("pipe close");
            break;
        }
        if(res < 0){
            perror("read");
            break;
        }
        if(res != sizeof(data)){
            DEBUG_INFO("length error");
            exit(1);
        }
        count++;
    }while(1);
    close(fd);
    if(count != TEST_MAX_COUNT){
        DEBUG_INFO("recv count error");
    }
    DEBUG_INFO("count = %d",count);
    exit(0);
    return NULL;
}
int main(int argc, char *argv[])
{
    int res = 0;
    int fds[2];
    res = pipe(fds);
    if(res < 0){
        perror("pipe");
        return -1;
    }
    pthread_t p1,p2;
    res = pthread_create(&p1,NULL,pthread_write,(void*)fds[1]);
    if(res == -1){
        perror("pthread_create");
        return -1;
    }
    pthread_detach(p1);
    res = pthread_create(&p2,NULL,pthread_read,(void*)fds[0]);
    if(res == -1){
        perror("pthread_create");
        return -1;

    }
    pthread_detach(p2);

    while(1){
        sleep(1);
    }
    return 0;
}

测试结果:

使用select操作读管道:

在此需要将管道读端设置为非阻塞模式

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)

#define TEST_MAX_COUNT 100000
struct mq_data{
    int len;
    int cmd;
    int seq;    
    char data[128];
};

//写线程
void *pthread_write(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    data.len = sizeof("456");
    memcpy(data.data,"456",sizeof("456"));
    for(int i=0; i<TEST_MAX_COUNT;i++){
       res = write(fd,&data,sizeof(data));
       if(res < 0){
        DEBUG_INFO("write:");
        break;
       }
    }
    close(fd);
    return NULL;
}
//读线程
void *pthread_read(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    int count = 0;
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(fd,&rset);
    int flag = fcntl(fd,F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd,F_SETFL,flag);
    while(1){
        res = select(fd + 1,&rset,NULL,NULL,NULL);
        if(res == -1){
            perror("selct");
            exit(-1);
        }
        if(FD_ISSET(fd,&rset)){
            int read_res = read(fd,&data,sizeof(data));
            if(read_res == 0){
                DEBUG_INFO("pipe close");
                break;
            }
            if(read_res < 0){
                perror("read");
                break;
            }
            if(read_res != sizeof(data)){
                DEBUG_INFO("length error");
                exit(1);
            }
            //DEBUG_INFO("%s",data.data);
            count++;
        }
    }
    close(fd);
    if(count != TEST_MAX_COUNT){
        DEBUG_INFO("recv count error");
    }
    DEBUG_INFO("count = %d",count);
    exit(0);
    return NULL;
}
int main(int argc, char *argv[])
{
    int res = 0;
    int fds[2];
    res = pipe(fds);
    if(res < 0){
        perror("pipe");
        return -1;
    }
    pthread_t p1,p2;
    res = pthread_create(&p1,NULL,pthread_write,(void*)fds[1]);
    if(res == -1){
        perror("pthread_create");
        return -1;
    }
    pthread_detach(p1);
    res = pthread_create(&p2,NULL,pthread_read,(void*)fds[0]);
    if(res == -1){
        perror("pthread_create");
        return -1;

    }
    pthread_detach(p2);

    while(1){
        sleep(1);
    }
    return 0;
}

执行结果:

使用select同时操作读写管道 

这个还可以验证写入长度是否是原子操作。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define DEBUG_INFO(format, ...) printf("%s - %d - %s :: "format"\n",__FILE__,__LINE__,__func__ ,##__VA_ARGS__)

#define TEST_MAX_COUNT 100000
struct mq_data{
    int len;
    int cmd;
    int seq;    
    char data[128];
};

//写线程
void *pthread_write(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    data.len = sizeof("456");
    memcpy(data.data,"456",sizeof("456"));
    int flag = fcntl(fd,F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd,F_SETFL,flag);
    fd_set wset;
    FD_ZERO(&wset);
    FD_SET(fd,&wset);
    int count = 0;
    for(int i=0; i<TEST_MAX_COUNT;i++){
        res = select(fd + 1,NULL,&wset,NULL,NULL);
        if(res == -1){
            perror("selct");
            exit(-1);
        }
        if(FD_ISSET(fd,&wset)){
            int write_res = write(fd,&data,sizeof(data));
            if(write_res < 0){
                DEBUG_INFO("write:");
                break;
            }
        }
    }
    close(fd);
    return NULL;
}
//读线程
void *pthread_read(void *arg){
    int fd = (int)arg;
    int res = 0;
    struct mq_data data;
    memset(&data, 0, sizeof(data));
    int count = 0;
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(fd,&rset);
    int flag = fcntl(fd,F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd,F_SETFL,flag);
    while(1){
        res = select(fd + 1,&rset,NULL,NULL,NULL);
        if(res == -1){
            perror("selct");
            exit(-1);
        }
        if(FD_ISSET(fd,&rset)){
            int read_res = read(fd,&data,sizeof(data));
            if(read_res == 0){
                DEBUG_INFO("pipe close");
                break;
            }
            if(read_res < 0){
                perror("read");
                break;
            }
            if(read_res != sizeof(data)){
                DEBUG_INFO("length error");
                exit(1);
            }
            // DEBUG_INFO("%s",data.data);
            count++;
        }
    }
    close(fd);
    if(count != TEST_MAX_COUNT){
        DEBUG_INFO("recv count error");
    }
    DEBUG_INFO("count = %d",count);
    exit(0);
    return NULL;
}
int main(int argc, char *argv[])
{
    int res = 0;
    int fds[2];
    res = pipe(fds);
    if(res < 0){
        perror("pipe");
        return -1;
    }
    pthread_t p1,p2;
    res = pthread_create(&p1,NULL,pthread_write,(void*)fds[1]);
    if(res == -1){
        perror("pthread_create");
        return -1;
    }
    pthread_detach(p1);
    res = pthread_create(&p2,NULL,pthread_read,(void*)fds[0]);
    if(res == -1){
        perror("pthread_create");
        return -1;

    }
    pthread_detach(p2);

    while(1){
        sleep(1);
    }
    return 0;
}

执行结果:

 第一次对比

 虽然有点牵强,也算是一种严谨性的体现吧。

小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/652794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小型极简主义 Linux 发行版:Peropesis

导读Peropesis 是 personal operating system 的转写简拼&#xff0c;一个小型、极简主义、基于命令行的 Linux 操作系统。目前仍是一个不完整的系统&#xff0c;但它正在不断改进。 此外&#xff0c;它是一个由自由软件创建的自由操作系统&#xff0c;在 GNU GPL 或 BSD 许可下…

csdn编辑模式

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

非授权访问测试-业务安全测试实操(9)

非授权访问测试, 越权测试 非授权访问测试 测试原理和方法 非授权访问是指用户在没有通过认证授权的情况下能够直接访问需要通过认证才能访问到的页面或文本信息。可以尝试在登录某网站前台或后台之后,将相关的页面链接复制到其他浏览器或其他电脑上进行访问,观察是否能访…

第二届BSN全球技术创新发展峰会在武汉成功举行

6月9日&#xff0c;由湖北省人民政府指导&#xff0c;湖北省发展改革委、国家信息中心联合主办&#xff0c;中国移动、中国电信、中国联通、武汉市江汉区人民政府、区块链服务网络&#xff08;BSN&#xff09;发展联盟、湖北省楚天云公司承办的第二届区块链服务网络&#xff08…

汽车功能安全中CPU lockstep技术浅析

知识的价值在于分享&#xff0c;欢迎大家批评指正&#xff0c;共同进步。 目录 1 功能安全 2 技术特性 3 安全系统架构 4 TI Hercules系列 4.1 TMS570安全概念基本原理 4.1.1 1oo1D双核安全概念 4.1.2 1oo1D优势 总结 参考文献 1 功能安全 根据ISO26262-2018&#xff0…

CVPR 2023 | 计算机视觉顶会亮点前瞻

在知识和技术都迅速更新迭代的计算机领域中&#xff0c;国际计算机视觉与模式识别会议&#xff08;CVPR&#xff09;是计算机视觉方向的“顶级流量”&#xff0c;引领着学科及相关领域的研究潮流。今天我们为大家带来5篇微软亚洲研究院被 CVPR 2023 收录的论文&#xff0c;主题…

【Linux】MySQL数据库 (一)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 MySQL数据库 一、数据库的基本概念二、数据库系统发展史1.第一代数据库2.第二代数据库3.第三代数据库 三、当今主流数据库介绍1.关系数据库2.非关系数据库 四、MySQL数据库管…

浅谈中移链中插件的功能及使用

中移链是在满足我国信息化监管需求、合规可控的前提下&#xff0c;打造的中国移动区块链服务平台。它允许使用插件来扩展其功能&#xff0c;以适应各种不同的使用场景。 什么是中移链插件呢&#xff1f;如果把中移链比作一个操作系统&#xff0c;那么插件就类比于操作系统上的…

chatgpt赋能python:Python编写选择题程序

Python编写选择题程序 Python是一种高级编程语言&#xff0c;由于其简洁、易读、易懂和易学的特性&#xff0c;使得Python成为了目前最流行的编程语言之一。Python的强大功能也使得它可以轻松地编写各种类型的程序&#xff0c;包括选择题程序。本文将介绍如何使用Python编写选…

SpringBoot全局异常页面处理学习

首先我们先在控制器中写一个异常&#xff0c;默认情况下我们的SpringBoot异常页面是这个样子的。 示例代码如下: import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;/*** author qinxun* date 202…

mov、mvn、cmp等ARM汇编指令集数据处理类指令(三星2440A)

文章目录 前言一、为什么要学习汇编&#xff1f;二、2440下常用汇编指令1. 汇编指令集合2. 2440编译&#xff08;汇编&#xff09;工程框架 三、汇编指令详解1. mov指令2. mvn3. add、sub、mul、rsb&#xff08;算术运算&#xff09;4. and、orr、eor、bic5. cmp、teq、tst5.1 …

视频会议需要什么设备?视频会议软硬件介绍

视频会议系统简介 视频会议系统是一种通过网络技术实现远程音视频通信的系统。它可以让不同地点的人们在同一时间进行实时的视音频交流&#xff0c;从而实现远程会议、远程教育、远程医疗以及最近比较新兴的直播等应用场景。 视频会议系统组成 视频会议系统通常包括摄像头、…

chatgpt赋能python:Python中如何精确到小数点

Python中如何精确到小数点 Python作为一种高级编程语言&#xff0c;被广泛应用于数据科学、网站开发、人工智能等领域。在处理数字时&#xff0c;精度一直是一个非常重要的问题。本文将介绍如何在Python中精确到小数点&#xff0c;并给出实例演示。 为什么需要精确到小数点 …

C++11学习笔记(4)——通用工具(下)

太长了&#xff0c;分两篇写吧 书接上回 4.数值极值 std::numeric_limits 是 C 标准库中定义的一个模板类&#xff0c;位于 头文件中。它提供了关于各种数值类型的属性和极值的信息。这些信息可以帮助我们在程序中进行数值处理时&#xff0c;了解特定类型的数值范围、精度以及…

Flutter如何获取屏幕的分辨率和实际画布的分辨率

Flutter如何获取分辨率 在Flutter中&#xff0c;你可以使用MediaQuery来获取屏幕的分辨率和实际画布的分辨率。 要获取屏幕的分辨率&#xff0c;你可以使用MediaQuery.of(context).size属性&#xff0c;它返回一个Size对象&#xff0c;其中包含屏幕的宽度和高度。下面是一个获…

Redis中常见的一些问题

缓存穿透问题 什么是缓存穿透&#xff1f; 例如当我们根据id查询一个数据的时候&#xff0c;但是这个数据本身不存在或者已经被删除之后&#xff0c;缓存中不存在&#xff0c;就会去查询数据库&#xff0c;但是不存在的数据不会缓存到数据库中&#xff0c;那么一旦大量的这个请…

层序遍历的应用——判断二叉树是否为完全二叉树

思维导图&#xff1a; 一&#xff0c;完全二叉树的特点 假如我们现在有一颗完全二叉树&#xff0c;那它应该长什么样呢&#xff1f; 它应该长这样&#xff1a; 这样&#xff1a; 这样&#xff1a; 如果不是一…

6 种方式读取 Springboot 的配置,老鸟都这么玩(原理+实战)

大家好&#xff0c;我是小富&#xff5e; 从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一&#xff0c;但就是这么常用的功能&#xff0c;仍然有很多开发者在这个方面踩坑。 我整理了几种获取配置属性的方式&#xff0c;目的不仅是要让大家学会如何使用&#…

Exiv2 —— exiv2介绍及下载搭建环境(Vs2017)

Exiv2介绍 Exiv2 是一个跨平台C库和一个命令行实用程序&#xff0c;用于管理图像元数据。它提供对Exif&#xff0c;IPTC和XMP元数据以及ICC配置文件的快速简便的读写访问。 嵌入到各种格式的数字图像中。 Exiv2 作为免费软件提供&#xff0c;用于许多项目 包括KDE和Gnome Deskt…

chatgpt赋能python:Python自动化脚本编写——让工作更高效

Python自动化脚本编写——让工作更高效 在当今的工作中&#xff0c;自动化脚本已经成为了一个不可或缺的工具。而Python作为一门脚本语言&#xff0c;它的开源、易用以及强大的库使得它成为了很多人使用自动化脚本的首选语言。 在本文中&#xff0c;我们将会探讨如何使用Pyth…