linux环形缓冲区kfifo实践3:IO多路复用poll和select

news2024/11/25 22:40:12

基础知识 

poll和select方法在Linux用户空间的API接口函数定义如下。

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

poll()函数的第一个参数fds是要监听的文件描述符集合,类型为指向struct pollfd的指针。struct pollfd数据结构定义如下。

struct pollfd {
    int  fd;
    short events;
    short revents;
};

fd表示要监听的文件描述符,events表示监听的事件,revents表示返回的事件。常用的监听的事件有如下类型(掩码)。

  •         POLLIN:数据可以立即被读取。
  •         POLLRDNORM:等同于POLLIN,表示数据可以立即被读取。
  •         POLLERR:设备发生了错误。
  •         POLLOUT:设备可以立即写入数据。

        poll()函数的第二个参数nfds是要监听的文件描述符的个数;第三个参数timeout是单位为ms的超时,负数表示一直监听,直到被监听的文件描述符集合中有设备发生了事件。

Linux内核的file_operations方法集提供了poll方法的实现。 

<include/linux/fs.h>
struct file_operations {
    …
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    …
};

        当用户程序打开设备文件后执行poll或者select系统调用时,驱动程序的poll方法就会被调用。设备驱动程序的poll方法会执行如下步骤。

1)在一个或者多个等待队列中调用poll_wait()函数。poll_wait()函数会把当前进程添加到指定的等待列表(poll_table)中,当请求数据准备好之后,会唤醒这些睡眠的进程。

2)返回监听事件,也就是POLLIN或者POLLOUT等掩码。因此,poll方法的作用就是让应用程序同时等待多个数据流。

驱动代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
#include <linux/poll.h>

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

struct ch5_kfifo_struct{
    struct miscdevice misc;
    struct file_operations fops;
    struct kfifo fifo;
    char buf[64];
    char name[64];
    wait_queue_head_t read_queue;
    wait_queue_head_t write_queue;
};

static int ch5_open (struct inode *inode, struct file *file){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)container_of(file->f_op,struct ch5_kfifo_struct,fops);
    file->private_data = p;
    DEBUG_INFO("major = %d, minor = %d\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
    DEBUG_INFO("name = %s",p->misc.name);
    return 0;
}

static int ch5_release (struct inode *inode, struct file *file){
    DEBUG_INFO("close");
    return 0;
}

static unsigned int ch5_poll(struct file *file, poll_table *wait){
    int mask = 0;
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    DEBUG_INFO("begin wait:%s",p->name);
    poll_wait(file, &p->read_queue, wait);
    poll_wait(file, &p->write_queue, wait);
    DEBUG_INFO("poll:%s",p->name);
    if (!kfifo_is_empty(&p->fifo)){
        mask |= POLLIN | POLLRDNORM;
        DEBUG_INFO("POLLIN:%s",p->name);
    }
        
    if (!kfifo_is_full(&p->fifo)){
        mask |= POLLOUT | POLLWRNORM;
        DEBUG_INFO("POLLOUT:%s",p->name);
    }
        
    return mask;
}

static ssize_t ch5_read (struct file *file, char __user *buf, size_t size, loff_t *pos){
    struct ch5_kfifo_struct *p __attribute__((unused)) = (struct ch5_kfifo_struct *)file->private_data;
    int ret;
    int actual_readed = 0;

    if(kfifo_is_empty(&p->fifo)){
        if(file->f_flags & O_NONBLOCK){
            DEBUG_INFO("kfifo is null");
            return -EAGAIN;
        }
        ret = wait_event_interruptible(p->read_queue,kfifo_is_empty(&p->fifo) == 0);
        if(ret){
            DEBUG_INFO("wait_event_interruptible error");
            return ret;
        }
        DEBUG_INFO("");
    }
    
    ret = kfifo_to_user(&p->fifo, buf, size, &actual_readed);
    if (ret){
        DEBUG_INFO("kfifo_to_user error");
		return -EIO;
    }
    
    DEBUG_INFO("size = %d,actual_readed = %d\n",size,actual_readed);

    if (!kfifo_is_full(&p->fifo)){
        wake_up_interruptible(&p->write_queue);
    }

    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_readed);
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("read p->buf = %s\n",p->buf);
    }
    *pos = *pos + actual_readed;
    return actual_readed;
}
static ssize_t ch5_write (struct file *file, const char __user *buf, size_t size, loff_t* pos){
    struct ch5_kfifo_struct *p = (struct ch5_kfifo_struct *)file->private_data;
    int actual_writed = 0;
    int ret;
    if(kfifo_is_full(&p->fifo)){
        if(file->f_flags & O_NONBLOCK){
            DEBUG_INFO("kfifo is full");
            return -EAGAIN;
        }
        ret = wait_event_interruptible(p->write_queue, kfifo_is_full(&p->fifo) == 0);
        if(ret){
            DEBUG_INFO("wait_event_interruptible error");
            return ret;
        }
        DEBUG_INFO("");
    }
    ret = kfifo_from_user(&p->fifo, buf, size, &actual_writed);
    if (ret){
        DEBUG_INFO("kfifo_from_user error");
		return -EIO;
    }
    
    DEBUG_INFO("actual_writed = %d\n",actual_writed);

    if (!kfifo_is_empty(&p->fifo)){
        wake_up_interruptible(&p->read_queue);
    }
    memset(p->buf,0,sizeof(p->buf));
    ret = copy_from_user(p->buf, buf, actual_writed);
    if(ret != 0){
        DEBUG_INFO("copy_from_user error ret = %d\n",ret);
    }else{
        DEBUG_INFO("write:p->buf = %s\n",p->buf);
    }
    *pos = *pos + actual_writed;
    return actual_writed;
}

struct ch5_kfifo_struct ch5_kfifo[8];
//  = {
//     .misc = { 
//         .name = "ch5-04-block",
//         .minor = MISC_DYNAMIC_MINOR,
//     },
//     .fops = {
//         .owner = THIS_MODULE,
//         .read = ch5_read,
//         .write = ch5_write,
//         .open = ch5_open,
//         .release = ch5_release,
//     },
// };

static int __init ch5_init(void){
    int ret = 0;
    int i = 0;
    struct ch5_kfifo_struct *p;

    DEBUG_INFO("start init\n");
    for(i = 0;i < sizeof(ch5_kfifo)/sizeof(ch5_kfifo[0]);i++){
        p = &ch5_kfifo[i];
        snprintf(p->name,sizeof(p->name),"ch5-05-poll-%d",i);
        p->misc.name = p->name;
        p->misc.minor = MISC_DYNAMIC_MINOR;

        p->fops.owner = THIS_MODULE;
        p->fops.read = ch5_read;
        p->fops.write = ch5_write;
        p->fops.open = ch5_open;
        p->fops.release = ch5_release;
        p->fops.poll = ch5_poll;

        p->misc.fops = &p->fops;
        ret = kfifo_alloc(&p->fifo,
                    8,
                    GFP_KERNEL);
        if (ret) {
            DEBUG_INFO("kfifo_alloc error: %d\n", ret);
            ret = -ENOMEM;
            return ret;
        }
        DEBUG_INFO("kfifo_alloc size = %d",kfifo_avail(&p->fifo));

        init_waitqueue_head(&p->read_queue);
        init_waitqueue_head(&p->write_queue);

        ret = misc_register(&p->misc);
        if(ret < 0){
            DEBUG_INFO("misc_register error: %d\n", ret);
            return ret;
        }
    }
    
    DEBUG_INFO("misc_register ok");
    return 0;
}

static void __exit ch5_exit(void){
    int i = 0;
    struct ch5_kfifo_struct *p;
    for(i = 0;i < sizeof(ch5_kfifo)/sizeof(ch5_kfifo[0]);i++){
        p = &ch5_kfifo[i];
        misc_deregister(&p->misc);
        kfifo_free(&p->fifo);
    }

    DEBUG_INFO("exit\n");
}

module_init(ch5_init);
module_exit(ch5_exit);

MODULE_LICENSE("GPL");

应用测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <linux/input.h>
#include <unistd.h>

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

int main(int argc, char**argv){
    char bufs[8][1024];
    char name[8][1024];
    int fd[8];
    int i = 0;
    int ret;
    int len;
    struct pollfd fds[8];

    for(i = 0;i < 8;i++){
        memset(name[i], 0, sizeof(name[i]));
        snprintf(name[i], sizeof(name[i]),"/dev/ch5-05-poll-%d",i);
        fd[i] = open(name[i],O_RDONLY | O_NONBLOCK);
        if(fd[i] < 0){
            perror("open");
            DEBUG_INFO("open %s failed",name[i]);
            return -1;
        }
        fds[i].fd = fd[i];
        fds[i].events = POLLIN;
        fds[i].revents = 0;
    }
    DEBUG_INFO("start poll\n");
    while(1){
        ret = poll(fds,8,-1);
        if(ret < 0){
            perror("poll");
            return 0;
        }
        DEBUG_INFO("ret %d\n",ret);
        for(i = 0;i < 8;i++){
            if(fds[i].revents & POLLIN){
                while(1){
                    memset(bufs[i],0,sizeof(bufs[i]));
                    len = read(fd[i],(void*)&bufs[i][0],sizeof(bufs[i]));
                    if(len <= 0){
                        DEBUG_INFO("read %s finish",name[i]);
                        break;
                    }
                    DEBUG_INFO("read %s :buf = %s",name[i],bufs[i]);
                }
            }
        }
    }
    return 0;
}

测试:

加载模块生成8个设备

 后台运行应用:

/mnt # ./app &
/mnt # [  519.185812] ch5_open:30 -- major = 10, minor = 58
[  519.185812] 
[  519.186175] ch5_open:31 -- name = ch5-05-poll-0
[  519.186849] ch5_open:30 -- major = 10, minor = 57
[  519.186849] 
[  519.187772] ch5_open:31 -- name = ch5-05-poll-1
[  519.190276] ch5_open:30 -- major = 10, minor = 56
[  519.190276] 
[  519.190553] ch5_open:31 -- name = ch5-05-poll-2
[  519.191129] ch5_open:30 -- major = 10, minor = 55
[  519.191129] 
[  519.191604] ch5_open:31 -- name = ch5-05-poll-3
[  519.192090] ch5_open:30 -- major = 10, minor = 54
[  519.192090] 
[  519.192283] ch5_open:31 -- name = ch5-05-poll-4
[  519.192759] ch5_open:30 -- major = 10, minor = 53
[  519.192759] 
[  519.193020] ch5_open:31 -- name = ch5-05-poll-5
[  519.193486] ch5_open:30 -- major = 10, minor = 52
[  519.193486] 
[  519.193677] ch5_open:31 -- name = ch5-05-poll-6
[  519.194148] ch5_open:30 -- major = 10, minor = 51
[  519.194148] 
[  519.194340] ch5_open:31 -- name = ch5-05-poll-7
main:38 -- start poll

[  519.199679] ch5_poll:43 -- begin wait:ch5-05-poll-0
[  519.200029] ch5_poll:46 -- poll:ch5-05-poll-0
[  519.200236] ch5_poll:54 -- POLLOUT:ch5-05-poll-0
[  519.200358] ch5_poll:43 -- begin wait:ch5-05-poll-1
[  519.200598] ch5_poll:46 -- poll:ch5-05-poll-1
[  519.200770] ch5_poll:54 -- POLLOUT:ch5-05-poll-1
[  519.201213] ch5_poll:43 -- begin wait:ch5-05-poll-2
[  519.201531] ch5_poll:46 -- poll:ch5-05-poll-2
[  519.201646] ch5_poll:54 -- POLLOUT:ch5-05-poll-2
[  519.201727] ch5_poll:43 -- begin wait:ch5-05-poll-3
[  519.201847] ch5_poll:46 -- poll:ch5-05-poll-3
[  519.201998] ch5_poll:54 -- POLLOUT:ch5-05-poll-3
[  519.202154] ch5_poll:43 -- begin wait:ch5-05-poll-4
[  519.202347] ch5_poll:46 -- poll:ch5-05-poll-4
[  519.202504] ch5_poll:54 -- POLLOUT:ch5-05-poll-4
[  519.202661] ch5_poll:43 -- begin wait:ch5-05-poll-5
[  519.202850] ch5_poll:46 -- poll:ch5-05-poll-5
[  519.203122] ch5_poll:54 -- POLLOUT:ch5-05-poll-5
[  519.203276] ch5_poll:43 -- begin wait:ch5-05-poll-6
[  519.203490] ch5_poll:46 -- poll:ch5-05-poll-6
[  519.203643] ch5_poll:54 -- POLLOUT:ch5-05-poll-6
[  519.203798] ch5_poll:43 -- begin wait:ch5-05-poll-7
[  519.203964] ch5_poll:46 -- poll:ch5-05-poll-7
[  519.204109] ch5_poll:54 -- POLLOUT:ch5-05-poll-7

 写数据

/mnt # echo "hello world" > /dev/ch5-05-poll-0 
[  576.205375] ch5_open:30 -- major = 10, minor = 58
[  576.205375] 
[  576.206863] ch5_open:31 -- name = ch5-05-poll-0
[  576.208285] ch5_write:122 -- actual_writed = 8
[  576.208285] 
[  576.208757] ch5_write:132 -- write:p->buf = hello wo
[  576.208757] 
[  576.209448] ch5_poll:43 -- begin wait:ch5-05-poll-0
[  576.209675] ch5_poll:46 -- poll:ch5-05-poll-0
[  576.209874] ch5_poll:49 -- POLLIN:ch5-05-poll-0
[  576.210058] ch5_poll:43 -- begin wait:ch5-05-poll-1
[  576.210291] ch5_poll:46 -- poll:ch5-05-poll-1
[  576.210451] ch5_poll:54 -- POLLOUT:ch5-05-poll-1
[  576.210645] ch5_poll:43 -- begin wait:ch5-05-poll-2
[  576.211496] ch5_poll:46 -- poll:ch5-05-poll-2
[  576.212140] ch5_poll:54 -- POLLOUT:ch5-05-poll-2
[  576.212315] ch5_poll:43 -- begin wait:ch5-05-poll-3
[  576.212517] ch5_poll:46 -- poll:ch5-05-poll-3
[  576.212707] ch5_poll:54 -- POLLOUT:ch5-05-poll-3
[  576.212928] ch5_poll:43 -- begin wait:ch5-05-poll-4
[  576.213169] ch5_poll:46 -- poll:ch5-05-poll-4
[  576.213333] ch5_poll:54 -- POLLOUT:ch5-05-poll-4
[  576.213515] ch5_poll:43 -- begin wait:ch5-05-poll-5
[  576.213752] ch5_poll:46 -- poll:ch5-05-poll-5
[  576.213869] ch5_poll:54 -- POLLOUT:ch5-05-poll-5
[  576.214067] ch5_poll:43 -- begin wait:ch5-05-poll-6
[  576.214238] ch5_poll:46 -- poll:ch5-05-poll-6
[  576.214392] ch5_poll:54 -- POLLOUT:ch5-05-poll-6
[  576.214545] ch5_poll:43 -- begin wait:ch5-05-poll-7
[  576.214963] ch5_poll:46 -- poll:ch5-05-poll-7
[  576.215300] ch5_poll:54 -- POLLOUT:ch5-05-poll-7
main:45 -- ret 1
[  576.216522] ch5_read:84 -- size = 1024,actual_readed = 8
[  576.216522] 
[  576.216920] ch5_read:95 -- read p->buf = hello wo
[  576.216920] 
[  576.217219] ch5_write:114 -- 
main:55 -- read /dev/ch5-05-poll-0 :buf = hello wo
[  576.217652] ch5_write:122 -- actual_writed = 4
[  576.217652] 
[  576.217989] ch5_write:132 -- write:p->buf = rld
[  576.217989] 
[  576.217989] 
main:55 -- read /dev/ch5-05-poll-0 :buf = rld[  576.218140] ch5_read:84 -- size = 1024,actual_readed = 4
[  576.218140] 

[  576.218294] ch5_read:95 -- read p->buf = rld
[  576.218294] 
[  576.218294] 

[  576.219434] ch5_read:67 -- kfifo is null
main:52 -- read /dev/ch5-05-poll-0 finish[  576.220169] ch5_release:36 -- close

[  576.220874] ch5_poll:43 -- begin wait:ch5-05-poll-0
[  576.221959] ch5_poll:46 -- poll:ch5-05-poll-0
[  576.222639] ch5_poll:54 -- POLLOUT:ch5-05-poll-0
[  576.224333] ch5_poll:43 -- begin wait:ch5-05-poll-1
[  576.225068] ch5_poll:46 -- poll:ch5-05-poll-1
[  576.225443] ch5_poll:54 -- POLLOUT:ch5-05-poll-1
[  576.225890] ch5_poll:43 -- begin wait:ch5-05-poll-2
[  576.226298] ch5_poll:46 -- poll:ch5-05-poll-2
[  576.226829] ch5_poll:54 -- POLLOUT:ch5-05-poll-2
[  576.227435] ch5_poll:43 -- begin wait:ch5-05-poll-3
/mnt # [  576.227639] ch5_poll:46 -- poll:ch5-05-poll-3
[  576.227892] ch5_poll:54 -- POLLOUT:ch5-05-poll-3
[  576.228124] ch5_poll:43 -- begin wait:ch5-05-poll-4
[  576.228344] ch5_poll:46 -- poll:ch5-05-poll-4
[  576.228573] ch5_poll:54 -- POLLOUT:ch5-05-poll-4
[  576.228902] ch5_poll:43 -- begin wait:ch5-05-poll-5
[  576.229155] ch5_poll:46 -- poll:ch5-05-poll-5
[  576.229349] ch5_poll:54 -- POLLOUT:ch5-05-poll-5
[  576.229573] ch5_poll:43 -- begin wait:ch5-05-poll-6
[  576.229761] ch5_poll:46 -- poll:ch5-05-poll-6
[  576.230005] ch5_poll:54 -- POLLOUT:ch5-05-poll-6
[  576.230233] ch5_poll:43 -- begin wait:ch5-05-poll-7
[  576.230421] ch5_poll:46 -- poll:ch5-05-poll-7
[  576.231095] ch5_poll:54 -- POLLOUT:ch5-05-poll-7

小结

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

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

相关文章

Netty的ReplayingDecoder分析

说明 io.netty.handler.codec.ReplayingDecoder是io.netty.handler.codec.ByteToMessageDecoder的一个子类&#xff0c;是一个抽象类&#xff0c;它将字节流解码成其它的消息。需要ReplayingDecoder的子类实现decode(ChannelHandlerContext ctx, ByteBuf in, List out)这个函数…

Selenium 自动化 | 案例实战篇

Chrome DevTools 简介 Chrome DevTools 是一组直接内置在基于 Chromium 的浏览器&#xff08;如 Chrome、Opera 和 Microsoft Edge&#xff09;中的工具&#xff0c;用于帮助开发人员调试和研究网站。 借助 Chrome DevTools&#xff0c;开发人员可以更深入地访问网站&#xf…

恒盛策略:快跌慢涨是主力洗盘?

当股市一直处于震荡状态&#xff0c;不断重复时。许多股民纷纷开端猜想股市未来走势&#xff0c;同时也有不少人议论着什么是“主力洗盘”和“快跌慢涨”。这儿&#xff0c;咱们来从多个视点来剖析这个问题。 首要&#xff0c;咱们需要了解“主力洗盘”和“快跌慢涨”两个概念。…

leetcode 475. 供暖器(java)

供暖器 供暖器题目描述双指针代码演示 双指针专题 供暖器 难度 - 中等 leetcode 475 题目描述 冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。 在加热器的加热半径范围内的每个房屋都可以获得供暖。 现在&#xff0c;给出位于一条水平线上的房屋 ho…

window下部署Yapi接口管理系统部署总结

window下部署Yapi接口管理系统部署总结 YApi 是高效、易用、功能强大的 api 管理平台&#xff0c;旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API&#xff0c;YApi 还为用户提供了优秀的交互体验&#xff0c;开发人员只需利用平…

使用几何和线性代数从单个图像进行 3D 重建

使用几何和线性代数从单个图像进行 3D 重建 萨蒂亚 一、说明 3D重构是一个挑战性题目&#xff0c;而且这个新颖的题目正处于启发和膨胀阶段&#xff1b;因此&#xff0c;各种各样的尝试层出不穷&#xff0c;本篇说明尝试的一种&#xff0c;至于其它更多的尝试&#xff0c;我们在…

uniapp+vue3项目中使用vant-weapp

创建项目 通过vue-cli命令行创建项目 Vue3/Vite版要求 node 版本^14.18.0 || >16.0.0 uni-app官网 (dcloud.net.cn) npx degit dcloudio/uni-preset-vue#vite my-vue3-project打开项目 点击顶部菜单栏终端/新建终端 执行安装依赖指令 yarn install 或 npm install 安装vant…

AI语音工牌在通讯行业营业大厅场景应用

在运营商营业大厅中&#xff0c;每天都有大量的客户来访咨询、办理业务。同时也会经常产生大量的客诉纠纷和服务差评。但因为缺乏有效的管理工具&#xff0c;加上线下沟通场景的数据采集难度高&#xff0c;数字化程度低&#xff0c;管理一直处于盲区。如何有效的管控营业厅人员…

从三个主要需求市场分析,VR全景创业的潜力发展

VR全景&#xff0c;5G时代朝阳产业&#xff0c;其实拍摄制作很简单&#xff0c;就是利用一套专业的相机设备去给商家拍摄&#xff0c;结合后期专业的3DVR全景展示拍摄制作平台&#xff0c;打造3D立体环绕的效果&#xff0c;将线下商家真实环境1&#xff1a;1还原到线上&#xf…

从C语言到C++_31(unordered_set和unordered_map介绍+哈希桶封装)

目录 1. unordered_set和unordered_map 1.1 unordered_map 1.2 unordered_set 1.3 unordered系列写OJ题 961. 在长度 2N 的数组中找出重复 N 次的元素 - 力扣&#xff08;LeetCode&#xff09; 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 217. 存在重…

NIO 非阻塞式IO

NIO Java NIO 基本介绍 Java NIO 全称 Java non-blocking IO&#xff0c;是指 JDK 提供的新 API。从 JDK1.4 开始&#xff0c;Java 提供了一系列改进的输入/输出的新特性&#xff0c;被统称为 NIO&#xff08;即 NewIO&#xff09;&#xff0c;是同步非阻塞的。NIO 相关类都被…

AIGC 浪潮下,鹅厂新一代前端人的真实工作感受

点击链接了解详情 原创作者&#xff1a;张波 腾小云导读 AIGC 这一时代潮流已然不可阻挡&#xff0c;我们要做的不是慌乱&#xff0c;而是把握住这个时代的机会。本文就和大家一起来探索在 AIGC 下&#xff0c;前端工程师即将面临的挑战和机遇。聊聊从以前到现在&#xff0c;A…

诸神之战:数字时代的低代码服务商与代理商究竟谁更强?

随着数字化转型浪潮的推进&#xff0c;企业对数字化应用开发的需求迅速增长。低代码作为一种新的软件开发范式&#xff0c;以其可视化和快速构建应用的能力&#xff0c;被广泛应用于成千上万家企业中。当低代码行业的逐渐发展成熟&#xff0c;越来越多的人看到了低代码的商业价…

使用乐观锁解决超卖问题

目录 什么是超卖&#xff1f; 乐观锁和悲观锁的定义 悲观锁&#xff1a; 乐观锁&#xff1a; 乐观锁的实现方式 1.版本号 2.CAS法 什么是超卖&#xff1f; 举个例子&#xff1a;订单系统中&#xff0c;用户在执行下单操作时&#xff0c;可能同一时间有无数个用户同时下单&…

平替版Airtag

Airtag是什么&#xff1f; AirTag是苹果公司设计的一款定位神奇&#xff0c;它通过一款纽扣电池进行供电&#xff0c;即可实现长达1-2年的关键物品的定位、查找的功能。 按照苹果公司自己的话说—— 您“丢三落四这门绝技&#xff0c;要‍失‍传‍了”。 AirTag 可帮你轻松追…

USB(二):Type-C

一、引脚定义 Type-C口有 4对TX/RX差分线&#xff0c;2对USB D/D-&#xff0c;1对SBU&#xff0c;2个CC&#xff0c;4个VBUS和4个地线Type-C母座视图&#xff1a; Type-C公头视图&#xff1a; 二、关键名词 DFP(Downstream Facing Port)&#xff1a; 下行端口&#xff0c…

【云原生】Pod的进阶

目录 一、资源限制二、重启策略三、健康检查 &#xff0c;又称为探针&#xff08;Probe&#xff09;3.1示例1&#xff1a;exec方式3.2示例2&#xff1a;httpGet方式3.3示例3&#xff1a;tcpSocket方式3.4示例4&#xff1a;就绪检测3.5示例5&#xff1a;就绪检测2 四、启动、退出…

设置VsCode 将打开的多个文件分行(栏)排列,实现全部显示

目录 1. 前言 2. 设置VsCode 多文件分行(栏)排列显示 1. 前言 主流编程IDE几乎都有排列切换选择所要查看的文件功能&#xff0c;如下为Visual Studio 2022的该功能界面&#xff1a; 图 1 图 2 当在Visual Studio 2022打开很多文件时&#xff0c;可以按照图1、图2所示找到自…

价格监测与数据分析的关系

所谓的价格监测&#xff0c;其实可以理解为是低价数据的监测&#xff0c;当监测价格时&#xff0c;其他页面上的商品数据也会被同时采集监测&#xff0c;如标题、库存、销量、评价等内容&#xff0c;所以品牌在做电商价格监测时&#xff0c;其实也可以对数据进行分析。 力维网络…

【React学习】—jsx语法规则(三)

【React学习】—jsx语法规则&#xff08;三&#xff09; 一、jsx语法规则&#xff1a; 1、定义虚拟DOM&#xff0c;不要写引号&#xff0c; 2、标签中混入JS表达式要用{} 3、样式的类名指定不要用class&#xff0c;要用className 4、内联样式&#xff0c;要用style{{key:value}…