(三)進程管理

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.      用戶進程祖先(1號進程, systemd);
  2.      內核進程祖先(2號進程, kthreadd)
  3.       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. 線程棧上的本地數據:如函數執行過程中的局部變量
  2. 在整個進程裏共享的全局數據:如全局變量
  3. 線程私有數據
//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);
}

 

總結

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章