1-进程
进程编译:程序的二进制格式 ELF
(Executeable and Linkable Format) 这个格式可以根据编译的结果不同,分为不同的格式。
可重定位 .o 文件(ELF 第一种格式)
先做预处理,然后编译的.o文件 就是第一种类型
格式如下
.rel.text 和 .rel.data 标注了哪些函数/数据需要重定位
这些节的元数据信息也需要有一个地方保存,就是最后的节头部表(Section Header Table)。
- 在这个表里面,每一个 section 都有一项,在代码里面也有定义 struct elf32_shdr 和 struct elf64_shdr。
- 在 ELF 的头里面,有描述这个文件的节头部表的位置,有多少个表项等等信息
可执行文件(ELF 第二种格式)
要函数可被调用, 要以库文件的形式存在, 最简单是创建静态链接库 .a 文件(Archives)
- 通过 ar 创建静态链接库, 通过 gcc 提取库文件中的 .o 文件, 链接到程序中
- 链接合并后, 就可以定位到函数/数据的位置, 形成可执行文件
共享对象 .so 文件(ELF 第三种格式)
默认情况下,系统在 /lib 和 /usr/lib 文件夹下寻找动态链接库。找不到就会报错
我们可以设定 LD_LIBRARY_PATH 环境变量,程序运行时会在此环境变量指定的文件夹下寻找动态链接库。
稍有不同的是:
- 增加了 .interp 段, 里面是 ld_linux.so (动态链接器)
- 增加了两个节 .plt(过程链接表)和 .got.plt(全局偏移表)一个动态链接函数对应 plt 中的一项 plt[x], plt[x] 中是代理代码, 调用 got 中的一项 got[y]
- - 起始, got 没有动态链接函数的地址, 都指向 plt[0], plt[0] 又调用 got[2], got[2]指向 ld_linux.so
- - ld_linux.so 找到加载到内存的动态链接函数的地址, 并将地址存入 got[2]
加载 ELF 文件到内存
SYSCALL_DEFINE3 ->do_execve->do_execveat_common->exec_binprm->search_binary_handler
进程树
- ps -ef: 用户进程不带中括号, 内核进程带中括号
有三类进程:
- 用户进程祖先(1号进程, systemd);
- 内核进程祖先(2号进程, kthreadd)
- tty ? 一般表示后台服务
总结
一个进程从代码到二进制到运行时的一个过程
2-线程
线程的创建和运行过程
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_OF_TASKS 5 void *downloadfile(void *filename) { printf("I am downloading the file %s!\n", (char *)filename); sleep(10); long downloadtime = rand()%100; printf("I finish downloading the file within %d minutes!\n", downloadtime); pthread_exit((void *)downloadtime); } int main(int argc, char *argv[]) { char files[NUM_OF_TASKS][20]={"file1.avi","file2.rmvb","file3.mp4","file4.wmv","file5.flv"}; pthread_t threads[NUM_OF_TASKS]; int rc; int t; int downloadtime; pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_JOINABLE); for(t=0;t<NUM_OF_TASKS;t++){ printf("creating thread %d, please help me to download %s\n", t, files[t]); rc = pthread_create(&threads[t], &thread_attr, downloadfile, (void *)files[t]); if (rc){ printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } pthread_attr_destroy(&thread_attr); for(t=0;t<NUM_OF_TASKS;t++){ pthread_join(threads[t],(void**)&downloadtime); printf("Thread %d downloads the file %s in %d minutes.\n",t,files[t],downloadtime); } pthread_exit(NULL); }
线程的数据
数据细分成三类
- 线程栈上的本地数据:如函数执行过程中的局部变量
- 在整个进程里共享的全局数据:如全局变量
- 线程私有数据
//1-线程都有自己的栈空间 //通过命令 ulimit -a 查看,默认情况下线程栈大小为 8192(8MB)。 //我们可以使用命令 ulimit -s 修改。 #线程栈,可以通过下面这个函数 pthread_attr_t,修改线程栈的大小 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
//线程私有数据(Thread Specific Data),可以通过以下函数创建 int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) //key 一旦被创建,所有线程都可以访问它,但各线程可根据自己的需要往 key 中填入不同的值, //这就相当于提供了一个同名而不同值的全局变量。 //我们可以通过下面的函数设置 key 对应的 value。 int pthread_setspecific(pthread_key_t key, const void *value) //获取 key 对应的 value void *pthread_getspecific(pthread_key_t key) //等到线程退出的时候,就会调用析构函数释放 value。
数据的保护
条件变量和互斥锁是配合使用的
[root@deployer createthread]# ./a.out // 招聘三个员工,一开始没有任务,大家睡大觉 No task now! Thread 3491833600 is waiting! No task now! Thread 3483440896 is waiting! No task now! Thread 3475048192 is waiting! // 老板开始分配任务了,第一批任务就一个,告诉三个员工醒来抢任务 I am Boss, I assigned 1 tasks, I notify all coders! // 员工一先发现有任务了,开始抢任务 Have task now! Thread 3491833600 is grabing the task ! // 员工一抢到了任务 A,开始干活 Thread 3491833600 has a task A now! // 员工二也发现有任务了,开始抢任务,不好意思,就一个任务,让人家抢走了,接着等吧 Have task now! Thread 3483440896 is grabing the task ! No task now! Thread 3483440896 is waiting! // 员工三也发现有任务了,开始抢任务,你比员工二还慢,接着等吧 Have task now! Thread 3475048192 is grabing the task ! No task now! Thread 3475048192 is waiting! // 员工一把任务做完了,又没有任务了,接着等待 Thread 3491833600 finish the task A ! No task now! Thread 3491833600 is waiting! // 老板又有新任务了,这次是两个任务,叫醒他们 I am Boss, I assigned 2 tasks, I notify all coders! // 这次员工二比较积极,先开始抢,并且抢到了任务 B Have task now! Thread 3483440896 is grabing the task ! Thread 3483440896 has a task B now! // 这次员工三也聪明了,赶紧抢,要不然没有年终奖了,终于抢到了任务 C Have task now! Thread 3475048192 is grabing the task ! Thread 3475048192 has a task C now! // 员工一上次抢到了,这次抢的慢了,没有抢到,是不是飘了 Have task now! Thread 3491833600 is grabing the task ! No task now! Thread 3491833600 is waiting! // 员工二做完了任务 B,没有任务了,接着等待 Thread 3483440896 finish the task B ! No task now! Thread 3483440896 is waiting! // 员工三做完了任务 C,没有任务了,接着等待 Thread 3475048192 finish the task C ! No task now! Thread 3475048192 is waiting! // 又来任务了,这次是三个任务,人人有份 I am Boss, I assigned 3 tasks, I notify all coders! // 员工一抢到了任务 D,员工二抢到了任务 E,员工三抢到了任务 F Have task now! Thread 3491833600 is grabing the task ! Thread 3491833600 has a task D now! Have task now! Thread 3483440896 is grabing the task ! Thread 3483440896 has a task E now! Have task now! Thread 3475048192 is grabing the task ! Thread 3475048192 has a task F now! // 三个员工都完成了,然后都又开始等待 Thread 3491833600 finish the task D ! Thread 3483440896 finish the task E ! Thread 3475048192 finish the task F ! No task now! Thread 3491833600 is waiting! No task now! Thread 3483440896 is waiting! No task now! Thread 3475048192 is waiting! // 公司活越来越多了,来了四个任务,赶紧干呀 I am Boss, I assigned 4 tasks, I notify all coders! // 员工一抢到了任务 G,员工二抢到了任务 H,员工三抢到了任务 I Have task now! Thread 3491833600 is grabing the task ! Thread 3491833600 has a task G now! Have task now! Thread 3483440896 is grabing the task ! Thread 3483440896 has a task H now! Have task now! Thread 3475048192 is grabing the task ! Thread 3475048192 has a task I now! // 员工一和员工三先做完了,发现还有一个任务开始抢 Thread 3491833600 finish the task G ! Thread 3475048192 finish the task I ! // 员工三没抢到,接着等 No task now! Thread 3475048192 is waiting! // 员工一抢到了任务 J,多做了一个任务 Thread 3491833600 has a task J now! // 员工二这才把任务 H 做完,黄花菜都凉了,接着等待吧 Thread 3483440896 finish the task H ! No task now! Thread 3483440896 is waiting! // 员工一做完了任务 J,接着等待 Thread 3491833600 finish the task J ! No task now! Thread 3491833600 is waiting!
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_OF_TASKS 3 #define MAX_TASK_QUEUE 11 char tasklist[MAX_TASK_QUEUE]="ABCDEFGHIJ"; int head = 0; int tail = 0; int quit = 0; pthread_mutex_t g_task_lock; pthread_cond_t g_task_cv; void *coder(void *notused) { pthread_t tid = pthread_self(); while(!quit){ pthread_mutex_lock(&g_task_lock); while(tail == head){ if(quit){ pthread_mutex_unlock(&g_task_lock); pthread_exit((void *)0); } printf("No task now! Thread %u is waiting!\n", (unsigned int)tid); pthread_cond_wait(&g_task_cv, &g_task_lock); printf("Have task now! Thread %u is grabing the task !\n", (unsigned int)tid); } char task = tasklist[head++]; pthread_mutex_unlock(&g_task_lock); printf("Thread %u has a task %c now!\n", (unsigned int)tid, task); sleep(5); printf("Thread %u finish the task %c!\n", (unsigned int)tid, task); } pthread_exit((void *)0); } int main(int argc, char *argv[]) { pthread_t threads[NUM_OF_TASKS]; int rc; int t; pthread_mutex_init(&g_task_lock, NULL); pthread_cond_init(&g_task_cv, NULL); for(t=0;t<NUM_OF_TASKS;t++){ rc = pthread_create(&threads[t], NULL, coder, NULL); if (rc){ printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } sleep(5); for(t=1;t<=4;t++){ pthread_mutex_lock(&g_task_lock); tail+=t; printf("I am Boss, I assigned %d tasks, I notify all coders!\n", t); pthread_cond_broadcast(&g_task_cv); pthread_mutex_unlock(&g_task_lock); sleep(20); } pthread_mutex_lock(&g_task_lock); quit = 1; pthread_cond_broadcast(&g_task_cv); pthread_mutex_unlock(&g_task_lock); pthread_mutex_destroy(&g_task_lock); pthread_cond_destroy(&g_task_cv); pthread_exit(NULL); }
总结