当前位置: 首页 > news >正文

Linux -- 线程控制相关的函数

目录

pthread_create -- 创建线程

参数

返回值

 代码 -- 不传 args:

编译时带  -lpthread

运行结果 

为什么输出混杂?

如何证明两个线程属于同一个进程?

 

如何证明是两个执行流? 

什么是LWP?

代码 -- 传 args:

运行结果:

pthread_self -- 线程标识符

代码:

LWP标识符 和 线程标识符的区别

pthread_join -- 等待线程退出

 前言:主线程比新线程先退出

参数

返回值

 代码 -- 不获取退出状态

代码 -- 获取退出状态

 ​编辑

pthread_exit -- 终止线程

前言:新、主线程共享地址空间

参数

作用

代码 

pthread_cancel -- 取消线程

参数

返回值

代码


pthread_create -- 创建线程

#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

参数

thread: 指向一个 pthread_t 类型的指针,用于存储新创建线程的标识符,是输出型参数

attr: 指向一个 pthread_attr_t 类型的指针,这个参数可以用来设置线程的属性,如栈大小、调度策略等。如果不需要特别设置线程属性,可以传递 NULL

start_routine: 这是一个函数指针,指向新线程开始执行的函数。该函数必须接受一个 void* 类型的参数,并返回一个 void* 类型的结果。

arg: 这个参数将被传递给 start_routine 函数作为其唯一的参数。如果你不想传递任何参数,可以使用 NULL

返回值

如果函数调用成功,返回值为 0

如果发生错误,返回值为一个非零的错误代码

 代码 -- 不传 args:

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;void* newthreadRun(void* args)
{while(1){cout<<"I am new thread"<<endl;sleep(1);}
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,nullptr);while(1){cout<<"I am main thread"<<endl;sleep(1);}return 0;
}

编译时带  -lpthread

这里需要了解一点小故事,用户知道线程和进程,但不知道轻量级进程,而Linux中没有真线程,Linux中没有线程相关的系统调用,只有轻量级进程的系统调用,为了让用户和系统达成一致,系统将轻量级进程的系统调用进行封装,转换成线程相关的接口语义提供给用户,也就有了pthread库(即原生线程库),这个库既不属于C语言,也不属于C++,所以在Linux系统中编写多线程时,都必须在编译时带上 -lpthread。

在 Linux 中编译使用 Pthreads 的程序时,通常需要链接 Pthreads 库。这可以通过编译命令中添加 -lpthread 选项来实现。-lpthread 选项不仅告诉编译器链接 Pthreads 库,还会启用一些必要的编译器选项,以确保线程支持的正确性和性能。 如果不使用 -lpthread 选项,编译器可能会报错或生成不可用的二进制文件。

thread:thread.ccg++ -o $@ $^ -std=c++11 -lpthread.PHONY:clean
clean:rm -f thread

运行结果 

可以看出,两个执行流同时输出信息。同时也可以看出,一开始新、主线程打印的消息混在一起了,后面才分开来,这是正常现象。

为什么输出混杂?

在多线程程序中,多个线程同时向终端输出信息时,可能会出现输出混杂的情况。这是因为每个线程的输出操作并不是原子的(原子操作,即要么完全执行,要么根本不执行),即一个线程可能在另一个线程已经开始输出但还没有完成输出时就开始了自己的输出,这种现象通常称为“输出交错”或“输出混杂”。 

如何证明两个线程属于同一个进程?

不传 args 版本的代码运行时,输入命令 ps ajx | head -1 && ps ajx | grep thread 筛选出 thread 进程,可以看出只有一个进程被调度

如何证明是两个执行流? 

当代码运行起来时,输入命令 ps -aL | head -1 && ps -aL | grep thread 可以查看线程的信息,可以看出两个线程的 pid 一样,即属于同一个进程,而 LWP 不同,则说明一个进程中有两个执行流

ps -aL-a显示所有进程,包括其他用户的进程,-L 显示每个线程的详细信息。 

什么是LWP?

LWP(Light Weight Process)是轻量级进程的缩写,在 Linux 中,LWP 通常被称为“线程”

代码 -- 传 args:

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){std::cout<<threadname<<" is running: "<<cnt<<", pid: "<<getpid()<<" mythread id: "<<toHex(pthread_self())<<std::endl;sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");pthread_join(tid,nullptr);return 0;
}

运行结果:

pthread_self -- 线程标识符

#include <pthread.h>
pthread_t pthread_self(void);

该函数用于获取当前线程的标识符pthread_t 类型)。

代码:

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{while(1){cout<<"I am new thread, new thread tid: "<<toHex(pthread_self())<<", pid: "<<getpid()<<endl;sleep(1);}
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,nullptr);while(1){cout<<"I am main thread, main thread tid: "<<toHex(pthread_self())<<", pid: "<<getpid()<<endl;sleep(1);}return 0;
}

可以看出,新、主线程的线程标识符 tid 的值不一样,同时也可以看出,LWP 和线程标识符 tid的值是不一样的

LWP标识符 和 线程标识符的区别

 LWP(Light Weight Process)标识符和线程标识符(Thread Identifier,TID)在数值上通常是不一样的。虽然它们在概念上密切相关,但它们表示的是不同的标识符,用途和获取方式也有所不同。

pthread_join -- 等待线程退出

 前言:主线程比新线程先退出

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;//新线程运行5秒while(cnt--){std::cout<<threadname<<" is running: "<<cnt<<", pid: "<<getpid()<<" mythread id: "<<toHex(pthread_self())<<std::endl;sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");sleep(1);//因为主线程没有阻塞等待新线程,1秒后,主线程先退出了std::cout<<"main thread quit"<<std::endl;return 0;
}

因为主线程没有阻塞等待新线程退出,1秒后,主线程退出了,主线程退出了就等同于整个进程退出了,分配给进程的资源都被释放了,所以所有的线程都要退出,所以新线程还没执行完就被退出了,通常需要主线程最后结束。线程的退出也需要wait,不然会发生内存泄漏问题。


#include <pthread.h>int pthread_join(pthread_t thread, void **value_ptr);

该函数用于等待指定的线程终止,并获取该线程的退出状态。 

参数

thread:要等待的线程的标识符pthread_t 类型,可以调用 pthread_self 函数获取)。

value_ptr输出型参数,用于存储线程的退出状态。如果不需要获取退出状态,可以传递 NULL

返回值

等待线程退出成功返回 0。 

等待线程退出失败返回非零错误码

 代码 -- 不获取退出状态

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){std::cout<<threadname<<" is running: "<<cnt<<", pid: "<<getpid()<<" mythread id: "<<toHex(pthread_self())<<std::endl;sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");int n=pthread_join(tid,nullptr);//获取返回值std::cout<<"main thread quit, n="<<n<<std::endl;return 0;
}

新线程正常退出,故返回值为 0. 

代码 -- 获取退出状态

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){std::cout<<threadname<<" is running: "<<cnt<<", pid: "<<getpid()<<" mythread id: "<<toHex(pthread_self())<<std::endl;sleep(1);}return (void*)123;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");void* ret=nullptr;int n=pthread_join(tid,&ret);//ret强转为long long是为了避免精度损失std::cout<<"main thread quit, n="<<n<<",main thread get a ret:"<<(long long)ret<<std::endl;return 0;
}

线程的退出状态其实就是线程执行的任务函数的返回值。 

 

pthread_exit -- 终止线程

前言:新、主线程共享地址空间

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>
int g_val=100;
string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){printf("new thread, g_val:%d,&g_val:%p\n",g_val,&g_val);g_val++;//在新线程中改变g_val的值sleep(1);}return nullptr;
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");int cnt=10;while(cnt--){//主线程不改变g_val的值printf("main thread, g_val:%d,&g_val:%p\n",g_val,&g_val);sleep(1);}void* ret=nullptr;int n=pthread_join(tid,&ret);std::cout<<"main thread quit, n="<<n<<",main thread get a ret:"<<(long long)ret<<std::endl;return 0;
}

可以看出,新线程修改了 g_val 的值,主线程中 g_val 的值也被修改了,说明新、主线程共享了地址空间,看到的是同一个变量,而不是和进程一样,发生写时拷贝。

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>
int g_val=100;
string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){printf("new thread, g_val:%d,&g_val:%p\n",g_val,&g_val);g_val++;//故意对空指针进行解引用int *p=nullptr;*p=10;sleep(1);}return nullptr;
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");int cnt=10;while(cnt--){printf("main thread, g_val:%d,&g_val:%p\n",g_val,&g_val);sleep(1);}void* ret=nullptr;int n=pthread_join(tid,&ret);std::cout<<"main thread quit, n="<<n<<",main thread get a ret:"<<(long long)ret<<std::endl;return 0;
}

 

在新线程中故意对野指针进行解引用,结果新、主线程一起退出了,这是因为在同一个进程中运行的所有线程共享相同的地址空间,这意味着如果一个线程造成了段错误(segmentation fault),那么这个错误会影响到整个进程,而不仅仅是单个线程。操作系统通常会终止整个进程以防止进一步的损坏


#include <pthread.h>void pthread_exit(void *value_ptr);

参数

value_ptr:一个指向指针的指针,用于存储线程的退出状态

这个值可以被 pthread_join 函数捕获并使用。如果不需要传递退出状态,可以传递 NULL

作用

终止当前线程:调用 pthread_exit 的线程会立即终止其执行

传递退出状态:可以通过 value_ptr 参数传递一个退出状态,这个状态可以被 pthread_join 函数捕获。

代码 

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>
int g_val=100;
string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){printf("new thread, g_val:%d,&g_val:%p\n",g_val,&g_val);g_val++;sleep(1);}pthread_exit((void*)123);
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");void* ret=nullptr;int n=pthread_join(tid,&ret);std::cout<<"main thread quit, n="<<n<<",main thread get a ret:"<<(long long)ret<<std::endl;return 0;
}

pthread_cancel -- 取消线程

#include <pthread.h>int pthread_cancel(pthread_t thread);

参数

thread:要取消的线程的标识符pthread_t 类型)。

返回值

取消线程成功,返回 0

取消线程失败,返回非零错误码

代码

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>
int g_val=100;
string toHex(pthread_t tid)
{char buffer[64];snprintf(buffer,sizeof(buffer),"0x%lx",tid);return buffer;
}
void* newthreadRun(void* args)
{std:string threadname=(char*)args;int cnt=5;while(cnt--){printf("new thread, g_val:%d,&g_val:%p\n",g_val,&g_val);g_val++;sleep(1);}pthread_exit((void*)123);
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,newthreadRun,(void*)"thread-1");pthread_cancel(tid);void* ret=nullptr;int n=pthread_join(tid,&ret);std::cout<<"main thread quit, n="<<n<<",main thread get a ret:"<<(long long)ret<<std::endl;return 0;
}

线程的退出状态为 -1,表示线程被取消。

相关文章:

Linux -- 线程控制相关的函数

目录 pthread_create -- 创建线程 参数 返回值 代码 -- 不传 args&#xff1a; 编译时带 -lpthread 运行结果 为什么输出混杂&#xff1f; 如何证明两个线程属于同一个进程&#xff1f; 如何证明是两个执行流&#xff1f; 什么是LWP&#xff1f; 代码 -- 传 args&a…...

基于quasar,只选择年度与月份的组件

为什么要做 quasar是个基于vue的强大的UI开发库&#xff0c;它提供了非常多的组件&#xff0c;比如日期选择。但是有些时候只需要选择到月份就可以了&#xff0c;quasar中没有&#xff0c;所以自己动手写了一个。因为对界面编程我不熟悉&#xff0c;所以&#xff0c;如果你有更…...

健康养生:拥抱生活的艺术

健康养生&#xff1a;拥抱生活的艺术 在快节奏的现代生活中&#xff0c;健康已成为我们最宝贵的财富。健康养生&#xff0c;不仅仅是一种生活方式的选择&#xff0c;更是一种对待生活的态度&#xff0c;它关乎于如何在日常中寻找到平衡&#xff0c;让身心得以滋养&#xff0c;…...

注意力机制+时空特征融合!组合模型集成学习预测!LSTM-Attention-Adaboost多变量时序预测

注意力机制时空特征融合&#xff01;组合模型集成学习预测&#xff01;LSTM-Attention-Adaboost多变量时序预测 目录 注意力机制时空特征融合&#xff01;组合模型集成学习预测&#xff01;LSTM-Attention-Adaboost多变量时序预测效果一览基本介绍程序设计参考资料 效果一览 基…...

uniapp 微信小程序 均分数据展示

效果图 数据展示&#xff0c;可自行搭配 html <view class"num-wrapper"><view class"num-item" click.stop"routerGo(跳转的地址)"><text class"num">&#xffe5;{{ 要展示的数据 || 0}}</text><view…...

Nacos 3.0 考虑升级到 Spring Boot 3 + JDK 17 了!

Nacos 由阿里开源&#xff0c;是 Spring Cloud Alibaba 中的一个重要组件&#xff0c;主要用于发现、配置和管理微服务。 由于 Spring Boot 2 的维护已于近期停止&#xff0c;Nacos 团队考虑升级到 Spring Boot 3 JDK 17&#xff0c;目前正在征求意见和建议。 这其实是一件好…...

跟沐神学读论文-论文阅读管理

摘要 近期有读论文的需求&#xff0c;就需要去了解一下论文到底要怎么读&#xff0c;同一个系列之间的论文如何作整理和归纳&#xff0c;之前也有了解过市面上有成熟的论文阅读工具&#xff0c;但是对于学生党来讲没什么性价比&#xff0c;在B站上看到沐神有讲解他的思路Typor…...

Python 参数配置使用 XML 文件的教程 || Python打包 || 模型部署

当配置项存储在外部文件&#xff08;如 XML、JSON&#xff09;时&#xff0c;修改配置无需重新编译和发布代码。通过更新 XML 文件即可调整参数&#xff0c;无需更改源代码&#xff0c;从而提升开发效率和代码可维护性。 1. 为什么选择 XML 配置文件 XML 配置文件具有多种优点…...

[SV]如何在UVM环境中使用C Model

在UVM环境中使用C Memory 一、C语言实现Memory 1.1 代码说明 Memory 初始化: memory_init() 函数将内存空间初始化为 0,并初始化互斥锁。AXI 写操作 (axi_write): 检查地址范围是否合法。使用 memcpy 将数据从输入缓冲区写入模拟内存。使用互斥锁保证线程安全。AXI 读操作 …...

十大开源的Cursor AI替代方案

随着AI的兴起&#xff0c;所使用的工具也在不断进步。Cursor AI 作为一个强大的编码助手&#xff0c;已经成为开发人员不可或缺的工具。开源替代方案提供了透明性、个性化和成本效益。本文深入探讨了Cursor AI 的十大开源替代方案&#xff0c;这些方案将丰富您的编码体验&#…...

相机光学(四十六)——镜头马达(VCM)控制策略模式

One Step Mode、Linear Slope Control&#xff08;LSC&#xff09;和Acceleration Control是三种不同的控制模式&#xff0c;它们在控制策略和应用场景上有所区别。这些控制模式在VCM中的应用是为了提高其性能&#xff0c;减少振动&#xff0c;加快响应速度&#xff0c;并提高定…...

专业140+总分410+浙江大学842信号系统与数字电路考研经验浙大电子信息与通信工程,真题,大纲,参考书。

考研落幕&#xff0c;本人本中游211&#xff0c;如愿以偿考入浙江大学&#xff0c;专业课842信号系统与数字电路140&#xff0c;总分410&#xff0c;和考前多次模考预期差距不大&#xff08;建议大家平时做好定期模考测试&#xff0c;直接从实战分数中&#xff0c;找到复习的脉…...

了解ARM的千兆以太网——RK3588

1. 简介 本文并不重点讲解调试内容&#xff0c;重点了解以太网在ARM设计中的框架以及在设备树以及驱动的一个整体框架。了解作为一个驱动开发人员当拿到一款未开发过的ARM板卡应该怎么去把网卡配置使用起来。 2. 基础知识介绍 在嵌入式ARM中实现以太网的解决方案通常有以下两种…...

JavaFX使用jfoenix的UI控件

jfoenix还是一个不错的样式&#xff0c;推荐使用&#xff0c;而且也可以支持scene builder中的拖拖拽拽 需要注意的是过高的javafx版本可能会使得某些样式或控件无法使用 比如alert控件&#xff0c;亲测javaFX 19版本可以正常使用 1.在pom.xml中引入依赖 GitHub地址https://gi…...

Linux(Ubuntu)命令大全——已分类整理,学习、查看更加方便直观!(2024年最新编制)

Hello! 认真好学的小伙伴们&#xff0c;大家好呀&#xff08;Respect~&#xff09;&#xff01;我是 H u a z z i Huazzi Huazzi&#xff0c;欢迎观看本篇博客&#xff0c;接下来让我们一起来学习 Ubuntu命令大全 吧&#xff01;祝你有所收获&#xff01; 文章目录 前言&#x…...

单片机:实现教学上下课的自动打玲(附带源码)

单片机实现教学上下课的自动打铃 在学校或其他教育机构中&#xff0c;定时的打铃系统被广泛应用&#xff0c;用于提醒学生和老师上下课的时间。一个简单的自动打铃系统可以通过单片机实现&#xff0c;结合蜂鸣器和定时器控制&#xff0c;可以在设定的时间点自动打铃&#xff0…...

进程通信方式---共享映射区(无血缘关系用的)

5.共享映射区&#xff08;无血缘关系用的&#xff09; 文章目录 5.共享映射区&#xff08;无血缘关系用的&#xff09;1.概述2.mmap&&munmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理&#xff1a;共享映射区是将文件…...

深度学习实战智能交通计数

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对车辆目标数据集进行训练和优化&#xff0c;该数据集包含丰富的车辆目标图像样本…...

【MySQL】MySQL表的操作

【MySQL】MySQL表的操作 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;MySQL&#x1f34b; &#x1f33c;文章目录&#x1f33c; 1. 创建表 2. 查看表结构 3. 修改表 4. 删除表 1. 创建表 create table table_name(表名称)( fiel…...

Redis篇-12--数据结构篇4--Hash内存模型(数组,链表,压缩列表zipList,哈希表,短结构)

Redis的Hash数据结构用于存储键值对&#xff08;key-value形式&#xff09;的集合&#xff08;类似java中HashMap或对象&#xff09;。为了在保证高效性能的同时节省内存&#xff0c;Redis对Hash的底层实现进行了多种优化。特别是通过使用压缩列表&#xff08;ziplist&#xff…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...