首先明确一个概念,Linux系统中甚至没有真正的线程。不过,可以认为Linux是系统的线程是内核线程,所有调度是基于线程的。

1、线程分类

一个进程由于其运行空间的不同, 从而有内核线程用户进程的区分,进程和线程都被维护为一个task_struct结构,线程和进程被同等对待来进行调度

  • 内核线程运行在内核空间, 之所以称之为线程是因为它没有虚拟地址空间, 只能访问内核的代码和数据, 而用户进程则运行在用户空间, 但是可以通过中断, 系统调用等方式从用户态陷入内核态
  • 用户进程运行在用户空间上, 而一些通过共享资源实现的一组进程我们称之为线程组, Linux下内核其实本质上没有线程的概念, Linux下线程其实上是与其他进程共享某些资源的进程而已。但是我们习惯上还是称他们为线程或者轻量级进程

Linux将线程区分为3类:

(1)实时先入先出。

(2)实时轮转。

(3)分时。

实时先入先出有最高的优先级,不会被其他线程抢占,除非是另外一个刚刚准备好的且优先级更高的实时先入先出线程。

实时轮转线程与实时先入先出类似,不过有一个轮转体系,即分配一个时间片,时间到了就可以被抢占。时间片消耗完就进入实时轮转线程列表的末尾。其实,这两种都不是真的实时,因为执行的最后期限无法确定,只是比分时线程有更高的优先级。

实时线程的优先级从0-99,0是实时线程的最高优先级,99是实时线程的最低优先级。

传统的非实时线程,优先级从100-139。Linux系统根据非实时线程的优先级分配时间量。

2、调度队列和多CPU负载均衡

每个CPU有自己的调度队列,包括两个数组:活动的和过期失效的。每个数组包括了140个链表头,对应140个优先级的链表。

调度器从正在活动数组中选择一个优先级最高的任务,如果时间片耗尽失效,就加入到过期失效数组中。如果进程在时间片内被阻塞,那么在时间片失效之前,等待的事件发生就可以继续运行,放回到正在活动的数组中。如果活动数组没有任务了,调度器交换指针,使得活动数组和失效数组调换。

不同的优先级被赋予不同的时间片长度,优先级越高的进程,时间片越长。

如果每个CPU调度队列的大小很不均衡,就会触发内核的load_balance函数。这个函数会把某个CPU处理器上过多的进程移到runqueue元素相对少的CPU处理器上。

3、线程优先级

Linux采用静态优先级动态优先级结合的方式。Linux采用了奖惩机制,目的在于奖励互动进程以及惩罚占用CPU的进程。一个进程初始被赋予了一个优先级,耗尽和阻塞会改变nice值,活动与过期进程转换时,动态改变进程优先级。

另外,对于多核处理器,运行队列数据结构与某一个处理器相对应,调度器尽量进行亲和调度,即将之前在某个处理器上运行过的任务再次调入该处理器。

调度器只考虑可以运行的任务,不可运行的任务和正在等待各种I/O操作的或内核事件的任务被放入等待队列中。每一种等待某种事件的任务组成一个等待队列。等待队列的头部包含一个指向任务链表的指针及一个自旋锁。

4、CPU时间片

内核在微观上,把CPU的运行时间分成许多分,然后安排给各个进程轮流运行,造成宏观上所有的进程仿佛同时在执行。双核CPU,实际上最多只能有两个进程在同时运行,大家在top、vmstat命令里看到的正在运行的进程,并不是真的在占有着CPU哈。

所以,一些设计良好的高性能进程,比如nginx,都是实际上有几颗CPU,就配几个工作进程,道理就在这。比如你的服务器有8颗CPU,那么nginx worker应当只有8个,当你多于8个时,内核可能会放超过多个nginx worker进程到1个runqueue里,会发生什么呢?就是在这颗CPU上,会比较均匀的把时间分配给这几个nginx worker,每个worker进程运行完一个时间片后,内核需要做进程切换,把正在运行的进程上下文保存下来。假设内核分配的时间片是100ms,做进程切换的时间是5ms,那么进程性能下降还是很明显的,跟你配置的worker有关,越多下降得越厉害。

当然,这是跟nginx的设计有关的。nginx是事件驱动的全异步进程,本身设计上就几乎不存在阻塞和中断,nginx的设计者就希望每一个nginx worker可以独占CPU的几乎全部时间片,这点就是nginx worker数量配置的依据所在。

当然,实际的运行进程里,大部分并不是nginx这种希望独占CPU全部时间片的进程,许多进程,比如vi,它在很多时间是在等待用户输入,这时vi在等待IO中断,是不占用时间片的,内核面对多样化的进程,就需要技巧性的分配CPU时间片了。

 
 参考:
https://www.cnblogs.com/lustar/p/7716165.html

【Linux内核】CPU和线程的更多相关文章

  1. LINUX内核CPU负载均衡机制【转】

    转自:http://oenhan.com/cpu-load-balance 还是神奇的进程调度问题引发的,参看Linux进程组调度机制分析,组调度机制是看清楚了,发现在重启过程中,很多内核调用栈阻塞在 ...

  2. linux内核中创建线程方法

    1.头文件 #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_ ...

  3. linux内核--进程与线程

    http://blog.csdn.net/yusiguyuan/article/details/12154823 在<linux内核设计与实现>中第三章讲解了进程管理,在关于进程和线程的概 ...

  4. linux内核中创建线程方法【转】

    本文转载自:https://www.cnblogs.com/Ph-one/p/6077787.html 1.头文件 #include <linux/sched.h> //wake_up_p ...

  5. Linux内核:kthread_create(线程)、SLEEP_MILLI_SEC

    转自:http://blog.csdn.net/guowenyan001/article/details/39230181 一.代码 #include <linux/module.h> # ...

  6. Linux内核剖析 之 进程简单介绍

    1.概念 1.1  什么是进程?     进程是程序运行的一个实例.能够看作充分描写叙述程序已经运行到何种程度的数据结构的汇集.     从内核观点看.进程的目的就是担当分配系统资源(CPU时间,内存 ...

  7. Linux内核设计基础(十)之内核开发与总结

    (1)Linux层次结构: (2)Linux内核组成: 主要由进程调度(SCHED).内存管理(MM).虚拟文件系统(VFS).网络接口(NET)和进程间通信(IPC)等5个子系统组成. (3)与Un ...

  8. 《Linux内核设计与实现》第一二章笔记

    第一章 linux内核简介 每个处理器在任何时间点上的活动必然概括为下列三者: 运行于用户空间,执行用户进程 运行于内核空间,处于进程上下文,代表某个特定的进程执行 运行于内核空间,处于中断上下文,与 ...

  9. Linux内核分析 一二章读书笔记

    第一章 Linux内核简介 1.Unix (1)Unix系统很简洁 (2)在Unix中,所以东西都被当作文件对待,通过一套相同的系统调用接口来进行:open(),read(),write(),lsee ...

  10. 《LINUX内核设计与实现》第一、二章学习总结

    第一章 Linux内核简介 (一)Unix是一个强大.健壮和稳定的操作系统,特点是: Unix很简洁,仅仅提供几个几百个系统调用并且有一个非常明确的设计目的 在Unix中,所有的东西都被当作文件对待, ...

随机推荐

  1. 用Visual Studio编写UDF的一点小技巧(自动补全宏函数、变量)

    下载Visual Studio,安装VS 下载番茄助手(Visual Assist X),链接:www.wholetomato.com,然后安装番茄助手 打开VS

  2. Tcl二进制数据

    binary format 格式化描述符 参数1 参数2...参数N binary scan 二进制数据 格式化描述符 变量1 变量2 ... 变量N 格式化描述符由两部分组成,第一是格式化类型关键字 ...

  3. Linux 文件系统磁盘空间与连接文件

    磁盘与目录的容量 我们知道磁盘的整体数据hi在superblock块中,但是各文件的容量则在inode中记载. df:列出文件系统的整体磁盘使用量 由于df主要读取的数据几乎都是针对整个文件系统,因此 ...

  4. libusb: android上集成libusb库

    1. 下载libusb库. 可以到libusb库的官网(https://libusb.info/)或者是其官方的github仓库(https://github.com/libusb/libusb/re ...

  5. python实现读取并显示图片的两种方法

    https://www.cnblogs.com/lantingg/p/9259840.html 在 python 中除了用 opencv,也可以用 matplotlib 和 PIL 这两个库操作图片. ...

  6. openresty开发系列31--openresty执行流程

    openresty开发系列31--openresty执行流程 我们先看个例子 location /test {    set $a 32;    echo $a;    set $a 56;    e ...

  7. pm2 工具来管理 node 服务端

    如下: nodeServer.js 'use strict'; const http = require('http'); const server = http.createServer(funct ...

  8. 数据分析入门——pandas之DataFrame多层/多级索引与聚合操作

    一.行多层索引 1.隐式创建 在构造函数中给index.colunms等多个数组实现(datafarme与series都可以) df的多级索引创建方法类似: 2.显式创建pd.MultiIndex 其 ...

  9. [译]Pandas列数据展示不全解决方法?

    Pandas数据展示列太多会显示...不显示具体数据. 设置参数可以显示全部数据: pd.set_option('display.expand_frame_repr', False)

  10. 转 : 请问mysql如何确定一个库是主库还是从库。

    select user,host from mysql.user;SELECT Repl_slave_priv,Repl_client_priv,super_priv,host FROM mysql. ...