(三)进程管理

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

 

总结

 

 

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