小小书童观战Thread调度

作为一个已经被PHP阉割的码农来说,探讨这个话题其实还是有点吃力的。首先什么是调度,全国火车运营中心要管理和调度全国的火车运行,什么时候发车,什么时候让车,什么时候再启动出发,什么时候准点到达目的地。火车调度中心如果想调度这些火车它必须有以下信息才能调度: 车次(ID),车目前运行到哪里了(status),其他跟他行驶一条道的车目前是什么状态(other_threads) ..... 当运营中心有了全部火车的这些信息,再加上稳定的环境(不发生地震),基本上可以完成调度任务(当然实际情况要比这复杂地多)。

操作系统的调度其实跟火车的调度类似,就是要记住每一个线程的状态,根据一定的策略调度这些线程去完成每一个线程赋予的使命。C/C++的多线程调度就是基于操作系统来完成的。要搞清楚线程的调度过程,先弄明白两个东西: 用户线程和内核线程。因为用户线程是第三方库或者说是用户态完成的调度。内核线程是利用操作系统的调度来完成调度(他们的创建也是一样的)。

好,那我们先得去了解用户态线程如何调度,再了解内核态线程如何调度,最后用户态线程和内核态线程之间如何完成交互的。

先看下内核线程如何创建出来的,Linux发家史告诉我们linux2.4之前没有引入线程的概念,2.4之后linux-kernel才增加了轻量级进程(也就是我们所说的线程)。线程和进程对于linux来说都是进程,因为核心数据结构都是task_struct:

struct task_struct {

      struct thread_info *thread_info;  // 指向进程或者线程的基本信息

      struct mm_struct *mm; // 进程或者线程的页表和虚拟内存 

      struct mm_struct *active_mm; // 内核的页表目录

      struct fs_struct *fs; // 文件系统对象

      struct file_struct *files; // 句柄对象

      struct signal_struct *sinall; // 信号量

      usigned_int pid; 

      usigned_int tid;

      usigned_int tgid;

      usigned_int pgid;

      usigned_int sid;

        ..... 

}

结构体中存放了某个进程或者线程的所有信息。clone() --> do_fork() ---> copy_process(), copy_process()会创建并拷贝当前进程的tast_struct, 同时创建这个子进程的thread_info结构。将task_struct放到调度队列里面返回在队列里面的索引值,即pid。clone的时候根据参数来选择要不要共享打开的文件,文件系统信息,信号处理函数,进程的地址空间。这就是进程和线程不一样的本质所在。

内核线程的调度由操作系统的调度策略决定,操作系统的调度策略大致有:分时调度策略, 实时调度策略等等,这里不打算介绍这些。

再看下用户线程如何创建,用户态线程的创建通过pthread库提供的API函数来完成。码农最常用到的API有:

int   pthread_create( pthread_t *thread, const pthread_attr_t *attr, void* (*start_routine)(void*), void*arg );

int  pthread_cancel( pthread_t thread );

int  pthread_join( pthread_t **thread, void **retval);

int  pthread_detach( pthread_t  thread);

....

pthread_create函数的第一个参数thread存放创建出来的线程的ID,第二参数pthread_attr_t *attr定制各种线程属性而存在的,如:

1) __detachstate: 与进程中的其他线程脱离关系,默认情况下是:
PTHREAD_CREATE_JOINABLE表示不脱离进程,PTHREAD_CREATE_DETACHED表示脱离进程的管理,执行结束后资源自行释放
2) __schedpolicy:线程的调度策略,实时还是非实时,先入先出还是轮转
...

第三个参数是线程的入口函数的起始地址,第四个参数是线程入口函数的参数。入口函数的参数传递是一个参数的时候可以直接传递,多个参数的时候可以组装成一个struct传递。
pthread_create通过一层层的封装最终调用clone函数创建线程:__pthread_create_2_1 -> create_thread() -> do_clone,传给do_clone的标记是CLONE_VM , CLONE_FS , CLONE_FILES

pthread_cancel,pthread_join,pthread_detach函数都是在管理线程和创建线程的进程之间的关系,至于创建出来的n个线程如何调度,需要pthread库给出一个用户态线程调度策略。比方说:用户态线程发起了一个长时间的内核操作,那么用户态线程是一直占用CPU等待内核的返回吗?还是记住当前的线程的状态然后切换其他线程执行,等到内核返回的之后再将之前的线程调度回来再继续执行吗?还是其他的策略呢?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容