龙岩招聘求职网站有哪些,合肥网站制作方案,接单网,ui设计培训班哪家好目录 线程概要Linux内核线程实现原理线程的共享/不共享资源线程优缺点线程控制原语pthread_selfpthread_createpthread_exitpthread_joinpthread_cancel终止线程方式控制原语对比前情提要#xff1a; Linux用户级线程和内核级线程区别 线程概要 Linux内核线程实现原理 类Unix系… 目录 线程概要Linux内核线程实现原理线程的共享/不共享资源线程优缺点线程控制原语pthread_selfpthread_createpthread_exitpthread_joinpthread_cancel终止线程方式控制原语对比 前情提要 Linux用户级线程和内核级线程区别 线程概要 Linux内核线程实现原理 类Unix系统中早期是没有“线程”概念的80年代才引入借助进程机制实现出了线程的概念。因此在这类系统中进程和线程关系密切。 轻量级进程(light-weight process)也有PCB创建线程使用的底层函数和进程一样都是clone从内核里看进程和线程是一样的都有各自不同的PCB但是PCB中指向内存资源的三级页表是相同的进程可以蜕变成线程线程可看做寄存器和栈的集合在linux下线程最是小的执行单位进程是最小的分配资源单位查看线程命令ps -elf|grep thread 三级映射进程PCB -- 页目录(可看成数组首地址位于PCB中) -- 页表 -- 物理页面 -- 内存单元 线程的共享/不共享资源 线程共享资源线程不共享资源文件描述符表线程id每种信号的处理方式处理器现场和栈指针内核栈当前工作目录独立的栈空间用户空间栈用户ID和组IDerrno变量内存地址空间(.text/.data/.bss/heap/共享库)信号屏蔽字调度优先级线程优缺点 优点 1. 提高程序并发性 2. 开销小 3. 数据通信、共享数据方便 缺点 1. 库函数不稳定 2. 调试、编写困难、gdb不支持 3. 对信号支持不好 线程控制原语 pthread_self 获取线程ID。其作用对应进程中 getpid() 函数。 pthread_t pthread_self(void); 返回值成功0 失败无 线程IDpthread_t类型本质在Linux下为无符号整数(%lu)其他系统中可能是结构体实现 线程ID是进程内部识别标志。(两个进程间线程ID允许相同) pthread_create 创建一个新线程。 其作用对应进程中fork() 函数。 int pthread_create(pthread_t thread, const pthread_attr_t attr, void (start_routine) (void ), void arg); 返回值成功0 失败错误号 -----Linux环境下所有线程特点失败均直接返回错误号。 参数 pthread_t当前Linux中可理解为typedef unsigned long int pthread_t; 参数1传出参数保存系统为我们分配好的线程ID 参数2通常传NULL表示使用线程默认属性。若想使用具体属性也可以修改该参数。 参数3函数指针指向线程主函数(线程体)该函数运行结束则线程结束。 参数4线程主函数执行期间所使用的参数。 练习创建一个新线程打印线程ID。注意链接线程库 -lpthread #include stdio.h
#include pthread.h
#include unistd.hvoid *tfn(void *arg)
{printf(Im thread, Thread_ID %lu\n, pthread_self());return NULL;
}int main(void)
{pthread_t tid;pthread_create(tid, NULL, tfn, NULL);sleep(1);printf(I am main, my pid %d\n, getpid());return 0;
} 线程默认共享数据段、代码段等地址空间常用的是全局变量或者传参形式。而进程不共享全局变量只能借助mmap。 全局变量 #include stdio.h
#include pthread.h
#include stdlib.h
#include unistd.hint var 100;void *tfn(void *arg)
{var 200;printf(thread\n);return NULL;
}int main(void)
{printf(At first var %d\n, var);pthread_t tid;pthread_create(tid, NULL, tfn, NULL);sleep(1);printf(after pthread_create, var %d\n, var);return 0;
} 传参 #include func.hvoid *tfn(void *arg){int* var (int*)arg;*var 200;printf(thread\n);return NULL;
}int main()
{int var 100;printf(At first var %d\n, var);pthread_t tid;pthread_create(tid, NULL, tfn, var);sleep(1);printf(after pthread_create, var %d\n, var);return 0;
} pthread_exit 作用将单个线程退出 void pthread_exit(void *retval); 参数retval表示线程退出状态通常传NULL 线程中**禁止使用exit函数会导致进程内所有线程全部退出**。所以多线程环境中应尽量少用或者不使用exit函数取而代之使用pthread_exit函数将单个线程退出。任何线程里exit导致进程退出其他线程未工作结束主控线程退出时不能return或exit。 另注意pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的不能在线程函数的栈上分配因为当其它线程得到这个返回指针时线程函数已经退出了。 pthread_join 阻塞等待线程退出获取线程退出状态 其作用对应进程中 waitpid() 函数。 int pthread_join(pthread_t thread, void **retval); 成功0失败错误号 参数thread线程ID 【注意】不是指针retval存储线程结束状态。 对比记忆 进程中main返回值、exit参数--int等待子进程结束 wait 函数参数--int * 线程中线程主函数返回值、pthread_exit--void *等待线程结束 pthread_join 函数参数--void ** 调用该函数的线程将挂起等待直到id为thread的线程终止。thread线程以不同的方法终止通过pthread_join得到的终止状态是不同的总结如下 如果thread线程通过return返回retval所指向的单元里存放的是thread线程函数的返回值。如果thread线程被别的线程调用pthread_cancel异常终止掉retval所指向的单元里存放的是常数PTHREAD_CANCELED。如果thread线程是自己调用pthread_exit终止的retval所指向的单元存放的是传给pthread_exit的参数。如果对thread线程的终止状态不感兴趣可以传NULL给retval参数。#include stdio.h
#include unistd.h
#include pthread.h
#include stdlib.htypedef struct {int a;int b;
} exit_t;void *tfn(void *arg)
{exit_t *ret;ret malloc(sizeof(exit_t)); ret-a 100;ret-b 300;pthread_exit((void *)ret);
}int main(void)
{pthread_t tid;exit_t *retval;pthread_create(tid, NULL, tfn, NULL);/*调用pthread_join可以获取线程的退出状态*/pthread_join(tid, (void **)retval); //wait(status);printf(a %d, b %d \n, retval-a, retval-b);return 0;
} pthread_cancel 杀死(取消)线程 其作用对应进程中 kill() 函数。 int pthread_cancel(pthread_t thread); 成功0失败错误号 【注意】线程的取消并不是实时的而有一定的延时。需要等待线程到达某个取消点(检查点)。 类似于玩游戏存档必须到达指定的场所(存档点如客栈、仓库、城里等)才能存储进度。杀死线程也不是立刻就能完成必须要到达取消点。 取消点是线程检查是否被取消并按请求进行动作的一个位置。通常是一些系统调用creatopenpauseclosereadwrite..... 执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。 可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点可以通过调用pthreestcancel函数自行设置一个取消点。 被取消的线程 退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是-1。可在头文件pthread.h中找到它的定义#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join回收时得到的返回值为-1。 终止线程的三种方法。注意“取消点”的概念。 #include stdio.h
#include unistd.h
#include pthread.h
#include stdlib.hvoid *tfn1(void *arg)
{printf(thread 1 returning\n);return (void *)111;
}void *tfn2(void *arg)
{printf(thread 2 exiting\n);pthread_exit((void *)222);
}void *tfn3(void *arg)
{while (1) {//printf(thread 3: Im going to die in 3 seconds ...\n);//sleep(1);pthread_testcancel(); //自己添加取消点*/}return (void *)666;
}int main(void)
{pthread_t tid;void *tret NULL;pthread_create(tid, NULL, tfn1, NULL);pthread_join(tid, tret);printf(thread 1 exit code %d\n\n, (int)tret);pthread_create(tid, NULL, tfn2, NULL);pthread_join(tid, tret);printf(thread 2 exit code %d\n\n, (int)tret);pthread_create(tid, NULL, tfn3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, tret);printf(thread 3 exit code %d\n, (int)tret);return 0;
} 终止线程方式 总结终止某个线程而不终止整个进程有三种方法 从线程主函数return。这种方法对主控线程不适用从main函数return相当于调用exit。一个线程可以调用pthread_cancel终止同一进程中的另一个线程。线程可以调用pthread_exit终止自己。控制原语对比 进程 线程 fork pthread_create exit pthread_exit wait pthread_join kill pthread_cancel getpid pthread_self 命名空间转载于:https://www.cnblogs.com/Mered1th/p/10801287.html