外贸建英文网站的重要性广东深圳龙岗区天气

web/2025/10/3 23:05:03/文章来源:
外贸建英文网站的重要性,广东深圳龙岗区天气,如何做类似于淘宝的网站,全国企业信息公示系统查询 作者#xff1a;დ旧言~ 座右铭#xff1a;松树千年终是朽#xff0c;槿花一日自为荣。 目标#xff1a;理解【Linux】多线程——线程概念|进程VS线程|线程控制 毒鸡汤#xff1a;有些事情#xff0c;总是不明白#xff0c;所以我不会坚持。早安! 作者დ旧言~ 座右铭松树千年终是朽槿花一日自为荣。 目标理解【Linux】多线程——线程概念|进程VS线程|线程控制 毒鸡汤有些事情总是不明白所以我不会坚持。早安! 专栏选自Linux初阶 望小伙伴们点赞收藏✨加关注哟 ​​ 前言 早期我们的计算机还只能单个进程运行这样的话每个进程就只能独立存在不可以进行每个进程交互在这个基础上我们的先人大佬看看能不能多个进程同时运行也就有了现在的多进程那对比单个进程多进程有什么优势呢值不值得我们学习呢咱们带上这两个问题来康康Linux下的多线程。 ⭐主体 学习【Linux】多线程——线程概念|进程VS线程|线程控制咱们按照下面的图解 ​ 地址空间和页表 地址空间是进程能看到的资源窗口一个进程能看到代码区、共享区、内核区、堆栈区大部分的资源都是在地址空间上看到的。 页表决定进程真正拥有资源的情况当前进程认为自己有了4GB可是实际上用了多少由页表决定最终能用多少物理资源。 合理的对地址空间与页表进行资源划分我们就可以对一个进程所有的资源进行分类通过地址空间分为栈区、堆区…通过页表映射到不同的物理内存。 页表的映射 在32位平台下一共有2³²个地址也就意味着有2³²个地址需要被映射 地址空间一共有2³²个地址每个地址单位都是1字节而页表也得有2³²个条目每个地址都得经过页表映射都是页表的每个条目包括物理地址包括是否命中包括RWX权限包括U/K权限一个条目假设为6个字节样例数据所以光保存页表所需空间为24GB4GB约为40亿字节。 每一个表项中除了要有虚拟地址和与其映射的物理地址以外实际还需要有一些权限相关的信息如用户级页表和内核级页表实际就是通过权限进行区分的 ​ 每个应表项中存储一个物理地址和一个虚拟地址就需要8个字节考虑到还需要包含权限相关的各种信息这里每一个表项就按10个字节计算 这里一共有2³²个表项也就意味着存储这张页表需要用2³² * 10个字节也就是40GB而在32位平台下我们的内存可能一共就只有4GB也就是说我们根本无法存储这样的一张页表 二级页表 虚拟地址在被转化的过程中不是直接转化的而是拆分成了10 10 12以32位平台为例其页表的映射过程如下 选择虚拟地址的前10个比特位在页目录当中进行查找找到对应的页表。再选择虚拟地址的10个比特位在对应的页表当中进行查找找到物理内存中对应页框的起始地址。最后将虚拟地址中剩下的12个比特位作为偏移量从对应页框的起始地址处向后进行偏移找到物理内存中某一个对应的字节数据。  相关说明 物理内存实际是被划分成一个个4KB大小的页框的而磁盘上的程序也是被划分成一个个4KB大小的页帧的当内存和磁盘进行数据交换时也是以4KB大小为单位进行加载和保存的。4KB 2¹²个字节一个页框中有2¹²个字节而访问内存的基本大小是1字节因此一个页框中就有2¹²个地址于是就可以将剩下的12个比特位作为偏移量从页框的起始地址处开始向后进行偏移从而找到物理内存中某一个对应字节数据。  这实际上就是所谓的二级页表其中页目录项是一级页表页表项是二级页表 每一个表项还是按10字节计算页目录和页表的表项都是2¹º个因此一个表的大小就是2¹º也就是10个字节也就是10KB页目录有2¹º个表项也就意味着页表有2¹º个也就是说一级页表有1张二级页表有2¹º张总共算下来大概就是10MB内存消耗并不高因此Linux中实际就是这样映射的。  **注意**Linux中32位平台用的是二级页表64位平台用的是多级页表 ​ 进程基础概念 线程是什么 概念 在一个程序里的一个执行路线就叫做线程thread。更准确的定义是线程是“一个进程内部的控制序列 ”一切进程至少都有一个执行线程;线程在进程内部运行本质是在进程地址空间内运行在Linux系统中在CPU眼中看到的PCB都要比传统的进程更加轻量化透过进程虚拟地址空间可以看到进程的大部分资源将进程资源合理分配给每个执行流就形成了线程执行流不同平台的多线程底层实现策略不一样我们讨论Linux平台。 进程对应的模型进程的创建实际上伴随着其进程控制块task_struct、进程地址空间mm_struct以及页表的创建虚拟地址和物理地址就是通过页表建立映射的 进程内核数据结构代码和数据,每个进程都有自己独立的进程地址空间和独立的页表也就意味着所有进程在运行时本身就具有独立性我们在创建“进程”时只创建PCB并要求创建出来的PCB不在独立创建与父进程同享PCB那么创建的结果就是下面这样的 因为我们可以通过虚拟地址空间页表的方式对进程进行资源划分单个“进程”执行力度一定要比之前的进程要细。上图中每个线程都是当前进程里的一个执行流线程在进程内部运行线程在进程的地址空间内运行拥有该进程的一部分资源。 如何理解线程 每个进程都有自己独立的进程地址空间和独立的页表也就意味着所有进程在运行时本身就具有独立性。 在创建进程时它要创建PCB页表建立代码和数据的映射关系…所以创建一个进程的成本非常高。 如果创建进程时只创建task_struct并要求创建出来的task_struct和父task_struct共享进程地址空间和页表。 现在创建的进程不再给你独立分配地址空间和页表而是都指向同一块地址空间共享同一块页表。所以这四个task_struct看到的资源都是一样的后续可以通过某种方式把代码区拆分成4块让这四个task_struct执行不同的代码区域。上述的区域(数据区堆区栈区)也是类似处理方式。换言之后续创建的3个task_struct都各自有自己的一小份代码和数据把这样的一份task_struct称之为线程。其中每一个线程都是当前进程里面的一个执行流也就是常说的线程是进程内部的一个执行分支。 线程在进程内部运行本质就是线程在进程地址空间内运行也就是说曾经这个进程申请的所有资源几乎都是被所有线程共享的。 线程比进程更细是因为其执行的代码和数据更小了。线程的调度成本更低了是因为它将来在调度的时候核心数据结构(地址空间和页表)均不用切换了。 上述线程仅仅是在Linux下的实现不同平台对线程管理可能不一样。 如Windows有真正的有关多线程的数据结构。而Linux并没有真正的对线程创建对应的数据结构。Linux的线程是用进程PCB模拟的。所以Linux并不能直接提供线程相关的接口只能提供轻量级进程的接口。               在用户层实现了一套用户层多线程方案以库的方式提供给用户进行使用。               pthread线程库。 CPU视角下Linux下PCB 其他OS内的PCB。 Linux下的进程统一称之为轻量级进程。 线程优点 创建一个新线程的代价要比创建一个新进程小得多。与进程之间的切换相比线程之间的切换需要操作系统做的工作要少很多。线程占用的资源要比进程少很多。能充分利用多处理器的可并行数量。在等待慢速I/O操作结束的同时程序可执行其他的计算任务。计算密集型应用为了能在多处理器系统上运行将计算分解到多个线程中实现。I/O密集型应用为了提高性能将I/O操作重叠。线程可以同时等待不同的I/O操作。 线程缺点 性能损失 一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多那么可能会有较大的性能损失。这里的性能损失指的是增加了额外的同步和调度开销而可用的资源不变。 健壮性降低编写多线程需要更全面更深入的考虑在一个多线程程序里因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的换句话说线程之间是缺乏保护的。缺乏访问控制进程是访问控制的基本粒度在一个线程中调用某些OS函数会对整个进程造成影响。编程难度提高编写与调试一个多线程程序比单线程程序困难得多。 线程异常 线程一旦异常会导致整个进程整体退出 单个线程如果出现除零野指针问题导致线程崩溃进程也会随着崩溃。线程是进程的执行分支线程出异常就类似进程出异常进而触发信号机制终止进程进程终止该进程内的所有线程也就随即退出。 线程用途 合理的使用多线程能提高CPU密集型程序的执行效率合理的使用多线程能提高IO密集型程序的用户体验 如一边写代码一边下载开发工具就是多线程运行的一种表现 进程VS线程 进程和线程 进程是资源分配的基本单位 线程是调度的基本单位 线程ID一组寄存器栈errno信号屏蔽字调度优先级 为什么线程切换的成本更低 地址空间和页表不需要切换。CPU内部是有L1~L3 cache如果进程切换cache就立即失效新进程过来只能重新缓存。 进程和线程的资源共享 进程的多个线程共享同一地址空间因此Text Segment、Data Segment都是共享的 如果定义一个函数在各线程中都可以调用如果定义一个全局变量在各线程中都可以访问到。 除此之外各线程还共享以下进程资源和环境 文件描述符表。每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)。当前工作目录。用户id和组id。 补充说明 __thread int g_val 100; // 修饰全局变量让每一个线程各自拥有一个全局的变量 -- 线程的局部存储进程和线程的关系 关于进程线程的问题 如何看待之前学习的单进程 具有一个线程执行流的进程。 引入线程后如何重新理解之前的进程 红色方框框起来的内容将这个整体称作进程曾经理解的进程 内核数据结构 进程对应的代码和数据现在的进程从内核角度看承担分配系统资源的基本实体 一个进程内部一定存在多个执行流那么这些执行流在CPU角度有区别吗 没有任何区别CPU不关心当前是进程还是线程这样的概念只关心PCBCPU调度的时候照样以task_struct为单位来进行调度。 只是这里task_struct背后的代码和页表只是曾经的代码和页表的一小部分而已。所以CPU执行的只是一小块代码和数据但并不妨碍CPU执行其它执行流。所以就可以把原本串行的所有代码转变成并发或并行的让这些代码在同一时间点得以推进。 总结如下 以前CPU看到的所有的task_struct都是一个进程现在CPU看到的所有的task_struct都是一个执行流(线程) ​线程控制 POSIX线程库 使用 与线程有关的函数构成了一个完整的系列绝大多数函数的名字都是以“pthread_”开头的要使用这些函数库要通过引入头文pthread.h链接这些线程函数库时要使用编译器命令的“-lpthread”选项 pthread线程库是应用层的原生线程库 我们说过在Linux没有真正意义上的线程无法直接提供创建线程的系统接口只能给我们提供创建轻量级进程的接口。但是在用户的角度上当我们想创建一个线程时会使用thread_create这样的接口而不是我们上面所使用vfork函数用户不能直接访问OS所以OS在用户和系统调用之间提供了编写好的用户级线程库这个库一般称为pthread库。任何Linux操作系统都必须默认携带这个库这个库称为原生线程库。原生的线程库本质上就是对轻量级进程的系统调用clone进行了封装pthread_create使用户层模拟实现了一套线程相关的接口。我们认为的线程实际在OS内部会被转化成我们所谓的轻量级进程。 错误检查: 传统的一些函数是成功返回0失败返回-1并且对全局变量errno赋值以指示错误。pthreads函数出错时不会设置全局变量errno而大部分其他POSIX函数会这样做。而是将错误代码通过返回值返回。pthreads同样也提供了线程内的errno变量以支持其它使用errno的代码。对于pthreads函数的错误建议通过返回值判定因为读取返回值要比读取线程内的errno变量的开销更小。 创建线程——pthread_create pthread_create讲解 pthread_create:创建线程的函数 #include pthread.hint pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);thread:获取线程的ID该参数是一个输出型参数attr:用于设置创建线程的属性传入nullptr表示默认这个属性基本不管start_routine:函数地址表示线程启动后要执行的函数arg:传给线程例程的参数返回值成功返回0失败返回错误码 举个栗子 #include iostream #include pthread.h #include assert.h #include unistd.h using namespace std; void * thread_routine(void *args) {const char*name (const char*)args;while(true){cout这是新线程我正在运行!nameendl;sleep(1);} }int main() {pthread_t tid;int n pthread_create(tid,nullptr,thread_routine,(void*)thread one);assert(0n);(void)n;while(true){cout这是主线程我真正运行endl;sleep(1);}return 0; }这里编译运行需要注意这个接口是库给我们提供的使用的接口如果不是语言上的接口或者操作系统上的接口如果是库提供的那在编译时是不通过的我们需要找到这个库。-L找到库在哪里-I找到头文件在哪里但是这个库已经在系统里安装好了除了告诉库和头文件在哪之外还需要知道链接哪一个库 此时我们用ps axj命令查看当前进程的信息时虽然此时该进程中有两个线程但是我们看到的进程只有一个因为这两个线程都是属于同一个进程的 而使用ps -aL指令就可以显示当前的轻量级进程了 其中LWPLight Weight Process表示的就是轻量级进程的ID可以看到显示的两个轻量级进程的PID是相同的因为它们是属于同一个进程的。每个轻量级进程都有唯一的LWP。 注意主线程的PID和LWP是一样的。不一样的就是新线程。所以CPU调度的时候是以LWP为标识符表示特定一个执行流。线程一旦被创建几乎所有的资源都是被所有线程共享的。所以线程之间想交互数据就容易了直接就能看到。 线程也一定要有自己私有的资源 线程被调度就要有独立的PCB属性私有。线程切换时正在运行需要进行上下文保存要有私有的上下文结构。每个进程都要独立的运行每个线程都要有自己独立的栈结构。 主线程创建一批新线程 我们让主线程一次性创建十个新线程并让创建的每一个新线程都去执行start_routine函数也就是说start_routine函数会被重复进入即该函数是会被重入的 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:pthread_t tid;char namebuffer[64];};//创建一批新线程 void* start_routine(void* args) {sleep(1);ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutnew thread create success,name: td-namebuffer cnt : cnt--endl;sleep(1);}delete td;return nullptr; } int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);// sleep(1);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}while(true){coutnew thread create success,name: main threadendl;sleep(1);}return 0; } 并且start_routine是可重入函数没有产生二义性没有因为一个线程去影响另一个线程。并且在函数内定义的变量都是局部变量具有临时性在多线程情况下也没有问题。这也说明了每一个线程都有自己独立的栈结构 获取线程ID——pthread_self 获取线程ID1.创建线程时通过输出型参数获得2.通过pthread_self接口函数获得 #include pthread.h pthread_t pthread_self(void);我们可以打印出主线程打印出新线程的ID新线程打印自己的ID看是否相同结果是相同的 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;string changeId(const pthread_t thread_id) {char tid[128];snprintf(tid,sizeof(tid),0x%x,thread_id);return tid; } void* start_routine(void*args) {std::string threadname static_castconst char*(args);while(true){coutthreadname running ... changeId(pthread_self())endl;sleep(1);} } int main() {pthread_t tid;pthread_create(tid,nullptr,start_routine,(void*)thread 1);coutmain thread running ... new thread id: changeId(tid)endl;pthread_join(tid,nullptr);return 0; } 线程等待——pthread_join 概念 一个线程创建出来那就要如同进程一样也是需要被等待的。如果线程不等待对应的PCB没被释放也会造成类似僵尸进程的问题内存泄漏。所以线程也要被等待 获取新线程的退出信息回收新线程对应的PCB等内核资源防止内存泄漏。 可以不关心线程的退出信息。 pthread_join:等待线程的函数 #include pthread.h int pthread_join(pthread_t thread, void **retval);参数thread:被等待线程的IDretval:线程退出时的退出码信息void** retval:输出型参数主要用来获取线程函数结束时返回的退出结果。之所以是void**,是因为如果想作为输出型结果返回因为线程函数的返回结果是void*,而要把结果带出去就必须是void**,返回值线程等待成功返回0失败返回错误码 举个栗子 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:int number;pthread_t tid;char namebuffer[64];}; class ThreadReturn { public:int exit_code;int exit_result; }; //创建一批新线程 void* start_routine(void* args) {ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutcnt:cntcnt:cntendl;cnt--;sleep(1);}ThreadReturn* tr new ThreadReturn();tr-exit_code 1;//线程退出码tr-exit_result 100;//线程退出结果return (void*)tr;//return (void*)td-number;//waring void*ret (void*)td-number;8字节、4字节 } int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();td-number i1;snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}for(autoiter:threads){ThreadReturn*ret nullptr;int n pthread_join(iter-tid,(void**)ret);assert(n0);coutjoin : iter-namebuffer success,exit_code: ret-exit_code,exit_result: ret-exit_resultendl;delete iter;}coutmain thread quitendl;return 0; }总结 没有看到线程退出时对应的退出信号这是因为线程出异常收到信号整个进程都会退出所以退出信号要由进程来关心所以pthread_join默认会认为函数会调用成功不考虑异常问题异常问题是进程该考虑的问题。 线程终止——return、pthread_exit、pthread_cancel 一个新创建出来的线程如果想终止线程而不是整个进程有三种做法: 直接从线程函数结束return的时候线程就算终止了。线程可以自己调用pthread_exit函数终止自己。一个线程可以调用pthread_cancel函数终止同一进程中的另一个线程。 return终止线程 注意:exit不能用来终止线程因为exit是来终止进程的。任何一个执行流调用exit都会让整个进程退出所以终止线程不能采用exit而是采用return来终止线程。 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:pthread_t tid;char namebuffer[64];}; //创建一批新线程 void* start_routine(void* args) {sleep(1);ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutcnt:cntcnt:cntendl;cnt--;sleep(1);return nullptr;}delete td; }int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}while(true){coutnew thread create success,name: main threadendl;sleep(1);}return 0; }#include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:pthread_t tid;char namebuffer[64];}; //创建一批新线程 void* start_routine(void* args) {sleep(1);ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutcnt:cntcnt:cntendl;cnt--;sleep(1);return nullptr;}delete td; }int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}while(true){coutnew thread create success,name: main threadendl;sleep(1);}return 0; } 最终新建线程终止。 pthread_exit函数 pthread_exit函数的功能就是终止线程 #include pthread.h void pthread_exit(void *retval);retval:线程退出时的退出码信息默认设置为nullptr 举个栗子 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:pthread_t tid;char namebuffer[64];}; //创建一批新线程 void* start_routine(void* args) {sleep(1);ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutcnt:cntcnt:cntendl;cnt--;sleep(1);}delete td;pthread_exit(nullptr); } int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}while(true){coutnew thread create success,name: main threadendl;sleep(1);}return 0; } pthread_cancel 线程是可以被其他线程取消的但是线程要被取消前提是这个线程是已经运行起来了。pthread_create取消也是线程终止的一种 #include pthread.h int pthread_cancel(pthread_t thread);我们以取消一半的线程为例 #include iostream #include pthread.h #include assert.h #include unistd.h #include vector using namespace std;class ThreadData { public:int number;pthread_t tid;char namebuffer[64]; }; //创建一批新线程 void* start_routine(void* args) {ThreadData *td static_castThreadData *(args);int cnt 10;while(cnt){coutcnt:cntcnt:cntendl;cnt--;sleep(1);}return (void*)100; } int main() {vectorThreadData* threads; #define NUM 10for(int i 0;iNUM;i){ThreadData *td new ThreadData();td-number i1;snprintf(td-namebuffer,sizeof(td-namebuffer),%s:%d,thread,i1);pthread_create(td-tid,nullptr,start_routine,td);threads.push_back(td);}for(autoiter:threads){coutcreate thread: iter-namebuffer : iter-tid sucess endl;}sleep(5);//取消一半的线程for(int i 0;ithreads.size()/2;i){pthread_cancel(threads[i]-tid);coutptheread_cancel : threads[i]-namebuffer successendl;}for(autoiter:threads){void*ret nullptr;int n pthread_join(iter-tid,(void**)ret);assert(n0);coutjoin : iter-namebuffer success,exit_code: (long long)retendl;delete iter;}coutmain thread quitendl;return 0; } 线程如果是被取消的退出码是-1-1是一个宏PTHREAD_CANCELED我们可以查看定义 #define PTHREAD_CANCELED ((void *) -1)初步重新认识我们的线程库语言版 任何语言在Linux中如果要实现多线程必定要使用pthread库如何看待C11中的多线程C11的多线程在Linux环境中本质就是对pthread库的封装。 分离线程——pthread_detach 概念 线程是可以等待的等待的时候是join的等待的阻塞式等待。而如果线程我们不想等待不要等待该去进行分离线程处理。默认情况下新创建的线程是joinable的线程退出后需要对其进行pthread_join操作否则无法释放资源从而造成内存泄漏而如果我们不关心线程的返回值join是一种负担这个时候我们可以告诉OS当线程退出时自动释放线程资源这种策略就是线程分离。 phread_detach使用 #include pthread.h int pthread_detach(pthread_t thread);下面我们创建新线程让主线程与新线程运行起来主线程等待新线程退出等待完毕返回n而现在让创建的新线程进行分离按照我们的预料此时应该是等待失败 #include iostream #include pthread.h #include assert.h #include unistd.h #include string.h #include vector using namespace std;string changeId(const pthread_t thread_id) {char tid[128];snprintf(tid,sizeof(tid),0x%x,thread_id);return tid; } void*start_routine(void*args) {string threadname static_castconst char*(args);pthread_detach(pthread_self());//线程分离设置为分离状态int cnt 5;while(cnt--){coutthreadname running ... changeId(pthread_self())endl;sleep(1);}return nullptr; } int main() {pthread_t tid;pthread_create(tid,nullptr,start_routine,(void*)thread 1);string main_id changeId(pthread_self());coutmain thread running... new thread id:changeId(tid)main thread id: main_idendl;//一个线程默认是joinable的设置了分离状态不能够进行等待了int n pthread_join(tid,nullptr);coutresult:n: strerror(n)endl;return 0; } 结束语  今天内容就到这里啦时间过得很快大家沉下心来好好学习会有一定的收获的大家多多坚持嘻嘻成功路上注定孤独因为坚持的人不多。那请大家举起自己的小手给博主一键三连有你们的支持是我最大的动力回见。 ​​​

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

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

相关文章

东阿聊城做网站的公司北京推广平台

全世界只有3.14 % 的人关注了爆炸吧知识作业太少吃得太饱特斯拉是外星人吗?偶然点开这个问题,让超模君震惊得心律不齐。作为人类有史以来最伟大的科学家之一,特斯拉一度被称为“最接近神的人”。但估计特斯拉本人也没有想到,在他长…

asp的公司网站开源免费cms可商业用

描述 有2000001块石头放在一条数线上。这些石子的坐标是 −1000000,−999999,−999998,…,999999,1000000。 其中一些连续的 K 个石子被涂成黑色,其他的被涂成白色。 此外,我们还知道位于坐标 X 的石子被涂成了黑色。 按升序打印所有可能包含被涂成黑…

怎样创立一个网站排版设计素材

现象&#xff1a; 1、点击遮罩弹窗关闭&#xff0c;弹窗的视频已经用v-if销毁&#xff0c;但是后台会自己从头开始播放视频声音。但是此时已经没有视频dom 2、定时器在打开弹窗后3秒自动关闭弹窗&#xff0c;则正常没有问题。 原来的代码&#xff1a; //页面 <a click&quo…

泵阀网站建设网站建设数据库怎么弄

给定一个原串和目标串&#xff0c;能对源串进行如下操作&#xff1a; 1.在给定位置插入一个字符 2.替换任意字符 3.删除任意字符 要求完成一下函数&#xff0c;返回最少的操作数&#xff0c;使得源串进行这些操作后等于目标串。源串和目标串长度都小于2000。动态创建的了二维…

网站提交工具seo关键词排名优化哪好

declare global 如果&#xff0c;要在全局作用域中声明一个新的变量或函数&#xff0c;供整个项目中的多个模块使用。可以使用 declare global 来实现。 在一个全局声明文件中&#xff0c;如 globals.d.ts declare global {var globalVar: numberfunction globalFunction(): …

高端网站定制费用是多少网站中常用的英文字体

将变量包装在对象中 不要使用 console.log(url, url2, baz)&#xff0c;而是使用 console.log({ url, url2, baz })。 如果你比较这两者&#xff0c;你会发现这有多么有用&#xff1a;拥有 url 和 url2 键可以避免这两个 URL 之间的混淆。 在日志前加上唯一字符串前缀 在应用…

浙江省城乡建设网站个人网站下载

目录 一、性能指标 二、jmeter &#xff08;一&#xff09;JMeter 安装 &#xff08;二&#xff09;JMeter 压测示例 1、添加线程组 2、添加 HTTP 请求 3、添加监听器 4、启动压测&查看分析结果 &#xff08;三&#xff09;JMeter Address Already in use 错误解决 压力测…

游戏在线玩免费免登录seo整体优化步骤怎么写

【0】README 0.1&#xff09; 本文旨在总结 中缀表达式转后缀表达式并计算后缀表达式的值 的步骤&#xff0c;并给出源代码实现&#xff1b; 0.2&#xff09; 本文中涉及到的源代码均为原创&#xff0c;是对中缀转后缀和计算后缀的简单实现&#xff0c;&#xff08;旨在理清它…

做网站一条龙网站建设教程集体苏州久远网络

当我们想把视频中去掉声音&#xff0c;可能有多种原因&#xff0c;也许需要制作一个无声视频&#xff0c;或者想在视频中添加自己的音乐或解说&#xff0c;特别是一些搞笑解说&#xff0c;无论原因是什么&#xff0c;到底要怎么把视频中所有的声音都去除呢&#xff1f; 小编给…

平湖公司做网站南城网站建设公司如何

目录 一、循环单链表 1、循环单链表的定义&#xff1a; 2、循环单链表的优缺点&#xff1a; 二、循环单链表的基本操作算法&#xff08;C语言&#xff09; 1、宏定义 2、创建结构体 3、循环单链表的初始化 4、循环单链表的插入 5、求单链表长度 6、循环单链表的清空…

瓜果类网站建设方案网站建设有哪种方式

关于uniapp组件的坑 我有一个组件写的没什么问题,但是报下面这个错误 is not found in path “components/xxx/xxxx” (using by “components/yyy/yyy”) 最后经过排除发现命名需要驼峰命名法 我原本组件命名: 文件夹名 test_tttt 文件名 test_tttt.vue 不行 最后改成文件…

线上海报设计网站环保行业网站怎么做

1 就跟我房东说&#xff1a;现在打工人压力真大一样▼2 原来&#xff0c;连打工人都不配了吗&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 原来这才是家大叶大▼4 给女朋友拍照时的你&#xff01;&#xff08;via.刘一杭三三 &#xff09;▼5 当法…

html5网站建设加盟公司和企业的区别

在上一篇博客中&#xff0c;我介绍了用Tensorflow来重现GPT 1的模型和训练的过程。这次我打算用Pytorch来重现GPT 2的模型并从头进行训练。 GPT 2的模型相比GPT 1的改进并不多&#xff0c;主要在以下方面&#xff1a; 1. GPT 2把layer normalization放在每个decoder block的前…

企业微营销网站国外手机设计网站

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

青浦教育平台网站建设wordpress函数the_posts

项目多人协作的困扰 相信大家多多少少都遇到过&#xff0c;当主线分支的代码&#xff0c;合入到自己的分支的时候&#xff0c;如果这时候&#xff0c;主线中有一些依赖的更新或者添加或者删除&#xff0c;如果合入之后&#xff0c;没有及时的install的话&#xff0c;项目启动的…

dede网站seowordpress清理修订

Kimi 是当前国内相当火爆的 AI 产品&#xff0c;输出结果和使用体验都非常不错。 Kimi 开放了 API 接口&#xff0c;新用户注册后会免费赠送 15 元额度。 Kimi API 的网址&#xff1a; platform.moonshot.cn/console 这是光明正大的白嫖方式&#xff0c;一定不要错过哦。 如…

合肥网站建设是什么网站关键词代码怎么做

Redis 主从复制 redis 主从复制配置 redis 主从复制启动 redis 主从复制断开 redis 主从复制主从复制构特点主从复制的拓扑结构一主一从⼀主多从树状主从 主从复制原理数据同步psync 运行流程全量复制流程部分复制流程实时复制 关于从节点何时晋升成主节点总结 redis 主从复制 …

高端网站建设如何收费红酒商城网站建设

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据) 一、实验描述 网络分析模块用于实现基于网络数据集的网络分析功能,包括路径分析、服务区分析、最近设施点分析、OD成本矩阵分析、多路径配送分析、位置分配分析和高级网络的管理与创建等。 网络…

自创网站怎么赚钱常见的网页布局结构有哪些

题干&#xff1a; 给出长度为n的序列a, 求有多少对数对 (i, j) (1 < i < j < n) 满足 ai aj 为完全平方数。 输入描述: 第一行一个整数 n (1 < n < 105) 第二行 n 个整数 ai (1 < ai < 105) 输出描述: 输出一个整数&#xff0c;表示满足上述条件的数…

注册网站商城需要什么条件4399网页版入口

Akka演员承诺并发。 有什么更好的模拟方式&#xff0c;看看使用商品硬件和软件处理1000万条消息需要花费多少时间&#xff0c;而无需进行任何低级调整。我用Java编写了整个1000万条消息的处理过程&#xff0c;整个结果令我惊讶。 当我在具有Intel i5 – 4核&#xff0c;4 Gb RA…