【Linux】第二章 Linux进程与线程(下)

4. Linux内核级线程与用户级线程

POSIX线程调度是一个混合模型,既支持用户级也支持内核级的线程。在创建线程时对contentionscope属性可设置为:

  • PTHREAD_SCOPE_PROCESS。它表示新创建的线程与它所在的进程中的其他线程竞争处理器资源,等同用户级线程。
  • PTHREAD_SCOPE_SYSTEM。说明新创建的线程就像内核级线程一样在全系统的范围内竞争处理器资源。

(1) 内核级线程

  • 线程的创建、撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程。
  • 这些线程可以在全系统内进行资源的竞争。
  • 内核空间内为每一个内核级线程设置了一个线程控制块(TCB),内核根据该控制块,感知线程的存在,并进行控制。
  • 内核切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用SMP,即利用多核CPU。

在一定程度上类似于进程,只是创建、调度的开销要比进程小。有人做过一个实验,创建线程和进程所花时间开销之比为1:10。内核级线程创建代码如下:pthread_attr_t attr;pthread_attr_init(&attr);// 设置内核级的线程,以获取较高的响应速度pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);//创建线程ret = pthread_create(&iAcceptThreadId, &attr,AcceptThread, NULL);

(2) 用户级线程

优点

  • 内核资源的分配仍然是按照进程进行分配的;各个用户线程只能在进程内进行资源竞争。
  • 用户级线程的切换发生在用户空间,这样的线程切换至少比陷入内核要快一个数量级(不需要陷入内核、不需要上下文切换、不需要对内存高速缓存进行刷新,这就使得线程调度非常快捷)。创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多, 因为保存线程状态的过程和调用程序都只是本地过程。
  • 内核并不能看到用户线程。——>重要的区别
  • 用户级线程有比较好的可扩展性,线程能够利用的表空间和堆栈空间比内核级线程多,这是因为在内核空间中内核线程需要一些固定的表格空间和堆栈空间,如果内核线程的数量非常大,就会出现问题。
  • 可以在不支持线程的操作系统中实现。
  • 允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别。
  • 线程的调度不需要内核直接参与,控制简单。

缺点:

  • 一个线程阻塞,会阻塞该进程中其他所有的线程。
  • 如果一个线程开始运行,那么该进程中其他线程就不能运行,除非第一个线程自动放弃CPU。因为在一个单独的进程内部,没有时钟中断,所以不能用轮转调度(轮流)的方式调度线程,不能很好的利用多核CPU。

用户级线程创建代码如下:pthread_attr_t attr;pthread_attr_init(&attr);// 设置用户级的线程pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);//创建线程ret = pthread_create(&iAcceptThreadId, &attr,AcceptThread, NULL); 但目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM,即,Linux仅提供了内核级线程。运行下列程序,可观察运行结果。程序创建了4个用户级线程(0-3)和4个人内核级线程(4-8),但从运行结果来看,每个线程运行的时间大致相等。如果Linux实现了用户级线程,线程(0-3)执行需要更多的时间。可见在Linux中没有实现用户级线程。

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

#include <time.h>

int n;  //共享变量,对共享变量应互斥使用,为简化设计,

// 本程序不考虑互斥问题。(省略互斥机制),

void *fun(void *id) {

   int i, j, sum=0, num=0;

   time_t t;

   time(&t);

   printf("T%s:Start...\n",(char*)id);

   for (i=0; i<100 ; i++ ) {

       for(j=0; j<10000000; j++) {

           sum += 1;

       }

   }

   n++;

   printf("T%s, time:%ld\n",(char *)id, time(NULL)-t);

}

char tid[8][2];

int main(void) {

   pthread_t t[8];

   int i;

   pthread_attr_t attr;

   pthread_attr_init(&attr);

   // 设置用户级线程。

   pthread_attr_setscope(&attr,PTHREAD_SCOPE_PROCESS);

   for (i=0; i < 4; i++) {

       tid[i][0] = 48+i;

       pthread_create(&t[i],  &attr, fun, &tid[i]);

   }

   // 设置内核级的线程,以获取较高的响应速度

   pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);

   for (i=4; i < 8; i++) {

      tid[i][0] = 48+i;

      pthread_create(&t[i],  &attr, fun,tid[i]);

   }

   while(n!=8);

   return 0;

}
gcc test2.c -o test2 -lpthread

执行结果:

xianchen$ ./test2 
T1:Start...
T5:Start...
T2:Start...
T7:Start...
T0:Start...
T4:Start...
T6:Start...
T3:Start...
T2, time:2
T5, time:3
T6, time:3
T3, time:3
T4, time:3
T7, time:3
T1, time:3
T0, time:3
T0, time:3

猜你喜欢

转载自www.cnblogs.com/vx-cg248805770/p/11653265.html