保险网站定制网店运营培训
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:59
当前位置: 首页 > news >正文
保险网站定制,网店运营培训,单页销售网站制作制作,专门做mod的网站目录
- 线程控制 1.1 线程创建(pthread_create) 1.2 线程结束(pthread_exit) 1.3 线程等待(pthread_join) 1.4 线程取消(pthread_cancel结束) 1.5 线程tid(pthread_self()) 1.6 线程局部存储(__thread) 1.7 线程分离(pthread_detach)
- C的多线程
- 笔试选择题 答…目录
- 线程控制 1.1 线程创建(pthread_create) 1.2 线程结束(pthread_exit) 1.3 线程等待(pthread_join) 1.4 线程取消(pthread_cancel结束) 1.5 线程tid(pthread_self()) 1.6 线程局部存储(__thread) 1.7 线程分离(pthread_detach)
- C的多线程
- 笔试选择题 答案及解析 本篇完。 1. 线程控制 上一篇讲了线程/轻量级进程的概念这篇讲讲线程的控制退出等待…… 1.1 线程创建(pthread_create) 线程创建上一篇已经讲过了 创建线程使用到的库函数接口man pthread_create pthread_t* thread线程标识符tid是一个输出型参数。const pthread_attr_t* attr线程属性当前阶段一律设成nullptr。void* (*start_routine)(void )是一个函数指针线程执行的就是该函数中的代码。void arg传给线程启动函数的参数是上面函数指针指向函数的形参。返回值线程创建成功返回0失败返回错误码。 看一下上篇出现线程异常的场景 #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char *)args;while (true){cout name , pid: getpid() endl;sleep(1);static int cnt 0;if (cnt 7){int *p nullptr;*p 777;}} }int main() {pthread_t tid[5];char name[64];for (int i 0; i 5; i){snprintf(name, sizeof(name), %s-%d, thread, i); // 特定内容格式化到name中pthread_create(tid i, nullptr, threadRun, (void *)name);sleep(1); // 缓解传参的bug}while (true){cout main thread, pid: getpid() endl;sleep(1);}return 0; } 出现异常全部线程都退出了有没有办法只让其中一个线程退出 试试exit() #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char *)args;while (true){cout name , pid: getpid() endl;sleep(1);static int cnt 0;if (cnt 7){// int *p nullptr;// *p 777;exit(10);}} }int main() {pthread_t tid[5];char name[64];for (int i 0; i 5; i){snprintf(name, sizeof(name), %s-%d, thread, i); // 特定内容格式化到name中pthread_create(tid i, nullptr, threadRun, (void *)name);sleep(1); // 缓解传参的bug}while (true){cout main thread, pid: getpid() endl;sleep(1);}return 0; } 还是全部线程都退出了这也再次认识了exit();就是终止进程的所以不建议用。 1.2 线程结束(pthread_exit) 基于前面我们的threadRun函数还有个是函数指针的返回值返回个空指针试试 可以发现名字为thread-1的线程好像退出了其它线程没退出就创建一个新线程看看 #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char *)args;while (true){cout name , pid: getpid() endl;sleep(1);static int cnt 0;if (cnt 7){// int *p nullptr;// *p 777;// exit(10);return nullptr;}} }int main() {// pthread_t tid[5];// char name[64];// for (int i 0; i 5; i)// {// snprintf(name, sizeof(name), %s-%d, thread, i); // 特定内容格式化到name中// pthread_create(tid i, nullptr, threadRun, (void )name);// sleep(1); // 缓解传参的bug// }pthread_t tid;pthread_create(tid, nullptr, threadRun, (void)thread 1);while (true){cout main thread, pid: getpid() endl;sleep(1);}return 0; } 可以发现新线程退出了主线程还没退出。 POSIX线程库专门提供了一个接口来结束线程pthread_exit()结束线程man pthread_exit void* retval返回线程结束信息当前阶段设置成nullptr即可。 调用该接口的线程会结束。 #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char *)args;while (true){cout name , pid: getpid() endl;sleep(1);static int cnt 0;if (cnt 7){// int *p nullptr;// *p 777;// exit(10);//return nullptr;pthread_exit(nullptr);}} }int main() {// pthread_t tid[5];// char name[64];// for (int i 0; i 5; i)// {// snprintf(name, sizeof(name), %s-%d, thread, i); // 特定内容格式化到name中// pthread_create(tid i, nullptr, threadRun, (void )name);// sleep(1); // 缓解传参的bug// }pthread_t tid;pthread_create(tid, nullptr, threadRun, (void)thread 1);while (true){cout main thread, pid: getpid() endl;sleep(1);}return 0; } 同样7秒后新线程会调用该接口然后就只剩下主线程了新线程结束了。 1.3 线程等待(pthread_join) 和进程一样线程也是需要等待的如果不等待会造成内存泄漏也就是结束掉的线程PCB不会被回收类似僵尸进程但是我们看不到没有回收的现象。 线程等待系统调用 第一个参数pthread_t thread要等待的线程tid。第二个参数void** retval线程结束的信息返回这是一个输出型参数。返回值等待成功返回0等待失败返回错误码。 演示一下使用 #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char )args;while (true){cout name , pid: getpid() endl;sleep(1);static int cnt 0;if (cnt 7){pthread_exit((void)777);}} }int main() {pthread_t tid;pthread_create(tid, nullptr, threadRun, (void*)thread 1);int *ret nullptr;pthread_join(tid, (void )ret); // 默认会阻塞等待新线程退出cout main quit …: new thead quit : (long long)ret endl;// linux下64位的指针是8个字节所以强转成long long 8个字节while (true){cout main thread, pid: getpid() endl;sleep(1);}return 0; } 可以看到主线程在执行到线程等待的时候会阻塞等待不再往下执行直到新线程都等待成功才会继续向下执行。 在主线程的栈区中有一个void类型的指针变量新线程中返回的void类型指针会放到这个ret中。 pthread线程库中有一个void 类型的二级指针变量retval。pthread_join()系统调用将主线程中void*类型的指针变量的地址传给了pthread线程库中的二级指针变量此时主线程就和线程库建立了联系。将新线程中返回到线程库中的void*指针变量中的返回值通过这种联系放到主线程中指针变量中—-也就是 *retval ret。 这样我们就可以成功的获取到新线程退出时的返回信息了桥梁就是pthread_join()系统调用。 在学习进程等待的时候我们不仅可以获得进程的退出信息还能获得进程的退出信号但是在线程退出时就没有获得线程退出信号这是为什么呢 因为信号是发给进程的整个进程都会被退出线程要退出信号也没有意义了。 而且pthread_join默认是能够等待成功的并不考虑异常的问题异常是进程要考虑的事线程不用考虑。 1.4 线程取消(pthread_cancel结束) Linux提供了线程结束的其它方式线程取消线程取消的接口 参数要取消的线程tid。返回值取消成功返回0失败返回错误码。 #include iostream #include unistd.h #include pthread.h using namespace std;void *threadRun(void *args) {const string name (char )args;while (true){cout name , pid: getpid() endl;sleep(1);} }int main() {pthread_t tid;pthread_create(tid, nullptr, threadRun, (void)thread 1);int cnt 0;while (true){cout main thread, pid: getpid() endl;sleep(1);if(cnt 5){break;}}pthread_cancel(tid);cout pthread cancel: tid endl;int *ret nullptr;pthread_join(tid, (void **)ret); // 默认会阻塞等待新线程退出cout main quit …: new thead quit : (long long)ret endl;// linux下64位的指针是8个字节所以强转成long long 8个字节return 0; } 可以看见如果一个线程是被取消结束的它的退出码就是-1。它其实是一个宏定义#defin PTHREAD_CANCELED -1。 线程取消也是一种线程结束的方式放在这里是为了能够通过线程等待看线程退出的退出码。 1.5 线程tid(pthread_self()) 有没有看见退出得到的tid是一个很大的整数这个整数实际上是一个地址。 我们还可以通过系统接口pthread_self在上面代码基础上打印自己的tid tid的值是一个地址。 我们知道Linux内核中是没有线程概念的也没有对应的TCB结构。 用户创建线程时使用的是POSIX线程库提供的接口。线程库中会调用clone()系统调用接口在内核中创建线程复用的PCB结构。这些轻量级进程共用一个进程地址空间。 系统中肯定不只一个线程存在大量的线程势必要管理起来管理的方式同样是先描述再组织。既然Linux内核中只有轻量级进程的PCB那么描述线程的TCB结构就只能存在于线程库中。 线程库中的TCB里存放着线程的属性这里的TCB被叫做用户级线程。 Linux线程方案用户级线程和用户关心的线程属性都在线程库中内核提供线程执行流的调度。 一个线程的所有属性描述是由两部组成的一部分就是在pthread线程库中的用户级线程另一部分就是Linux中的轻量级进程它们俩的比例大约是1比1。 pthread线程库从磁盘上加载到内存中后通过页表再将虚拟地址空间和物理地址映射起来。 线程库最终是映射在虚拟地址空间中的共享区中的mmap区域。 线程库是映射在共享区的那么线程库所维护的TCB结构也就一定在共享区。 如上图所示将映射到共享区的动态线程库放大。 线程库中存在多个TCB结构来描述线程。每个TCB的地址就是线程id。 线程tid的本质就是虚拟地址共享区中TCB结构体的地址。 线程的栈也在共享区中而不在栈中。 虚拟地址空间中的栈是主线程的栈共享区中动态库中的栈是新线程的栈。 所以说线程的栈结构是相互独立的因为存在于不同的TCB中主线程除外。 1.6 线程局部存储(thread) 在共享区线程库中的TCB里有一个线程的局部存储属性它是一个介于全局变量和局部变量之间线程特有的属性。 #include iostream #include unistd.h #include pthread.h using namespace std;int g_val 0;void *threadRun(void *args) {const string name (char )args;while (true){//cout name , pid: getpid() tid: pthread_self() endl;cout name - g_val: g_val g_val: g_val endl;sleep(1);} }int main() {pthread_t tid;pthread_create(tid, nullptr, threadRun, (void)thread 1);int cnt 0;while (true){cout main thread - g_val: g_val g_val: g_val endl;sleep(1);if(cnt 5){break;}}pthread_cancel(tid);cout pthread cancel: tid endl;int *ret nullptr;pthread_join(tid, (void **)ret); // 默认会阻塞等待新线程退出cout main quit …: new thead quit : (long long)ret endl;// linux下64位的指针是8个字节所以强转成long long 8个字节return 0; } 主线程和新线程打印的地址都是一样的说明主线程和新线程共用一个全局变量。 那如果此时新线程仍然想用这个变量名但是又不想影响其他线程也就是让这个全局变量独立出来该怎么办呢此时就可以使用线程的局部存储属性了。 在全局变量g_val前面加thread(两个下划线)此时这个全局变量就具有了局部存储的属性。 主线程和新线程打印出来的全局变量的地址不相同了说明此时用的并不是同一个全局变量。 而且新线程修改这个值主线程不受影响。 将全局变量或者static变量添加 thread设置位线程局部存储。 此时每个线程的TCB中都会有一份该变量相互独立并不会互相影响。 1.7 线程分离(pthread_detach) 前面线程等待的时候主线程就需要阻塞式等待线程的释放主线程什么都干不了。能不能像进程那样不需要阻塞式等待(将SIGCHID信号设置为忽略)等新线程结束以后自动释放呢?尤其是不需要关心线程返回值的时候join是一种负担。 当然可以将需要自动释放的线程设置成分离状态将线程设置成分离状态意味着不需要主线程再关心该线程的状态它会自动释放。 线程分离的接口man pthread_detach 参数 pthread_t thread要分离的线程tid。返回值 int成功返回0不成功返回错误码。 可以是线程组内其他线程对目标线程进行分离但一般是线程自己分离自己: #include iostream #include cerrno #include cstring #include unistd.h #include pthread.h using namespace std;thread int g_val 0;void *threadRun(void *args) {pthread_detach(pthread_self());const string name (char )args;while (true){//cout name , pid: getpid() tid: pthread_self() endl;cout name - g_val: g_val g_val: g_val endl;sleep(5);pthread_exit((void)777);} }int main() {pthread_t tid;pthread_create(tid, nullptr, threadRun, (void*)thread 1);int cnt 0;while (true){cout main thread - g_val: g_val g_val: g_val endl;sleep(1);if(cnt 5){break;}}int *ret nullptr; // 新线程自己分离了但是主线程非要等待呢int n pthread_join(tid, (void **)ret); // 默认会阻塞等待新线程退出if(n 0){cout main quit …: new thead quit : (long long)ret endl;}else{cout n : n errstring: strerror(n) endl;}// linux下64位的指针是8个字节所以强转成long long 8个字节return 0; } 可以看到此时主线程在进行线程等待的时候就会失败而且返回错误码。 2. C的多线程 C也是可以多线程编程的而且提供了多线程的库而无论什么编程语言什么库在Linux系统上的多线程本质上都是对pthread原生线程库的封装。 简单演示一下 Makefile mythread:mythread.ccg -o \( \)^ -stdc11 .PHONY:clean clean:rm -f mythread mythread.cc #include iostream #include thread #include unistd.h using namespace std;void fun() {while(true){cout hello new thread endl;sleep(1);} }int main() {std::thread t(fun);std::thread t1(fun);std::thread t2(fun);std::thread t3(fun);std::thread t4(fun);while(true){cout hello main thread endl;sleep(1);}t.join(); } 此时就发现运行不了了改下Makefile mythread:mythread.ccg -o \( \)^ -stdc11 -lpthread .PHONY:clean clean:rm -f mythread 此时程序就能正常运行了演示这个主要为了说明无论什么编程语言什么库在Linux系统上的多线程本质上都是对pthread原生线程库的封装。 3. 笔试选择题
- 进程和线程是操作系统中最基本的概念,下列有关描述错误的是 ( ) A.进程是程序的一次执行,而线程可以理解为程序中运行的一个片段 B.由于线程没有独立的地址空间,同一个进程的一组线程可以共享访问大部分该进程资源,这些线程之间的通信很高效 C.线程之间的通信简单(共享了虚拟地址空间及页表因此函数传参以及全局变量即可实现通信),而不同进程之间的通信更为复杂,通常需要调用内核实现 D.线程有独立的虚拟地址空间,但是拥有的资源相对进程来说,只有运行所必须的栈,寄存器等 2. 多线程中栈与堆的基本情况是 () A.多个线程共有一个栈各自有一个堆 B.多个线程共有一个栈, 共有一个堆 C.多个线程各自有一个栈共有一个堆 D.多个线程各自有一个栈, 各自有一个堆 3. 下面关于线程的叙述中正确的是() A.不论是系统支持线程还是用户级线程其切换都需要内核的支持 B.线程是资源的分配单位进程是调度和分配的单位 C.不管系统中是否有线程进程都是拥有资源的独立单位 D.在引入线程的系统中进程仍是资源分配和调度分派的基本单位 4. 下面有关线程的说法错误的是[多选] A.每个线程有自己独立的地址空间 B.耗时的操作使用线程提高应用程序响应 C.多CPU系统中使用线程提高CPU利用率 D.线程包含CPU现场可以独立执行程序 5 .关于进程和线程下列说法正确的是___[多选] A.线程是资源分配和拥有的单位 B.线程和进程都可并发执行 C.在linux系统中线程是处理器调度的基本单位 D.线程的粒度小于进程占用资源更少因此通常多线程比多进程并发性更高 E.不同的线程共享相同的栈空间 6. 下述有关Linux进程和线程的描述正确的有[多选] A.在linux 中进程比线程安全的原因是进程之间不会共享数据 B.进程有独立的地址空间线程没有单独的地址空间同一进程内的线程共享进程的地址空间 C.进程——资源分配的最小单位线程——程序执行的最小单位 D.进程和线程都有单独的地址空间 7. 关于多线程和多线程编程以下哪些说法正确的[多选] A.多进程之间的数据共享比多线程编程复杂 B.多线程的创建切换销毁速度快于多进程 C.对于大量的计算优先使用多进程 D.多线程没有内存隔离单个线程崩溃会导致整个应用程序的退出 8. 有关进程和线程的说法错误的是[多选] A.一个程序至少有一个进程一个进程至少有一个线程 B.操作系统的最小调度单位是进程 C.线程自己不拥有系统资源 D.一个线程可以创建和撤销另一个线程 9. 关于多线程和多进程编程下面描述正确的是 [多选] A.多进程里子进程可复制父进程的所有堆和栈的数据而线程会与同进程的其他线程共享数据但拥有自己的栈空间 B.线程因为有自己的独立栈空间且共享数据所有执行的开销相对较大同时不利于资源管理和保护 C.线程的通信速度更快切换更快因为他们在同一地址空间内且还共享了很多其他的进程资源比如页表指针这些是不需要切换的 D.线程使用公共变量/内存时需要使用同步机制因为他们在同一地址空间内 E.因多进程里每个子进程有自己的地址空间因此相互之间通信时线程不如进程灵活和方便 答案及解析 1. D D错误线程并没有独立的虚拟地址空间只是在进程虚拟地址空间中拥有相对独立的一块空间 2. C 线程独有栈寄存器信号屏蔽字errno…等信息因此各个线程各自有各自的栈区但是堆区共用 3. C A 用户态线程的切换在用户态实现不需要内核支持 B 进程是资源分配的基本单位线程是调度的基本单位 D 线程才是调度的基本单位 4. D A错误 线程只是在进程虚拟地址空间中拥有相对独立的一块空间但是本质上说用的是同一个地址空间 B正确 使用多线程可以更加充分利用cpu资源使任务处理效率更高进而提高程序响应 C正确 对于多核心cpu来说每个核心都有一套独立的寄存器用于进行程序处理因此可以同时将多个执行流的信息加载到不同核心上并行运行充分利用cpu资源提高处理效率 D错误 线程包含cpu现场但是线程只是进程中的一个执行流执行的是程序中的一个片段代码多个线程完整整体程序的运行 5. BCD A 线程是调度的基本单位 E 每个线程在进程虚拟地址空间中会分配拥有相对独立的栈空间而并不是共享栈空间这样会导致运行时栈混乱 6. BC A错误 进程比线程安全的原因是每个进程有独立的虚拟地址空间有自己独有的数据具有独立性不会数据共享这个太过宽泛与片面 D错误 进程有独立的地址空间但是同一个进程的线程之间共享同一个地址空间 7. ABD A正确 因为线程之间共享地址空间因此通信更加方便全局数据以及函数传参都可以实现而进程间则需要系统调用来完成 B正确 因为线程之间共享了进程中的大部分资源因此共享的数据不需要重新创建或销毁因此消耗上低于进程反之也就是速度快于进程 C错误 大量的计算使用多进程和多线程都可以实现并行/并发处理而线程的资源消耗小于多进程而稳定向较多进程有所不如因此还要看具体更加细致的需求场景 D正确 其实不仅仅是内存隔离的问题还有就是异常针对的是整个进程因此单个线程的崩溃会导致异常针对进程触发最终退出整个进程。 8. AB A错误 程序是静态的不涉及进程进程是程序运行时的实体是一次程序的运行 B错误 操作系统的最小调度单位是线程 C正确 进程是资源的分配单位所以线程并不拥有系统资源而是共享使用进程的资源进程的资源由系统进行分配 D正确 任何一个线程都可以创建或撤销另一个线程 9. ACD B 线程拥有自己的栈空间且共享数据没错但是资源消耗更小且便于进程内线程间的资源管理和保护否则会造成栈混乱 E 进程因为每个都有独立的虚拟地址空间因此通信麻烦需要调用内核接口实现。而线程间共用同一个虚拟地址空间通过全局变量以及传参就可实现通信因此更加灵活方便 本篇完。 下一篇零基础Linux_23(多线程)线程安全线程互斥线程同步。 2023.10.24能想到的三个节日记录一下各位程序员和准程序员节日快乐。
- 上一篇: 保险网站程序源码网站选择语言怎么做
- 下一篇: 保险网站建设的总体目标wordpress通知评论者
相关文章
-
保险网站程序源码网站选择语言怎么做
保险网站程序源码网站选择语言怎么做
- 技术栈
- 2026年03月21日
-
保险公司网站建设方案html5网站建设企业论文
保险公司网站建设方案html5网站建设企业论文
- 技术栈
- 2026年03月21日
-
保洁公司在哪个网站做推广比较好品牌推广策划
保洁公司在哪个网站做推广比较好品牌推广策划
- 技术栈
- 2026年03月21日
-
保险网站建设的总体目标wordpress通知评论者
保险网站建设的总体目标wordpress通知评论者
- 技术栈
- 2026年03月21日
-
保险网站建设方案泰安专业网页设计培训
保险网站建设方案泰安专业网页设计培训
- 技术栈
- 2026年03月21日
-
保险网站哪家好wordpress主题自定义
保险网站哪家好wordpress主题自定义
- 技术栈
- 2026年03月21日






