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); }
總結