实战:C语言实现用户态线程

0. 前言

一直以来,我们学习线程切换与调度,都是通过阅读操作系统书籍或 Linux 源码甚至反汇编 Window 内核代码。无论怎样,这些东西都很抽象,学习起来十分困难。另外,随着现代化编程语言逐渐流行,C++20 的正式发布,都离不开用户态线程这些基础知识。再比如 Golang 的 Goroutine,腾讯公司的开源的 libco,百度的 BRPC 中的 bthread,如果想深刻理解它们,都需要扎实的基本功。

会带你循序渐近的掌握下面的知识点:

  • 控制流切换原理
  • 上下文切换
  • 线程设计
  • 调度函数的封装与代码模块化
  • 线程的主动切换
  • 时间片轮转调度

本文实验环境:

  • ubuntu 16.04 32 位操作系统(读者请务必提前安装好);
  • 挑选一个你自己觉得好用的虚拟机软件,比如 VMWare;
  • 请把你的虚拟机环境配置成单核 CPU。
  • 学习时间:大于 5 小时

为什么使用 32 位系统?因为方便初学者学习,能更快速的掌握原理。

最终我们实验完成的效果应该是下面这个样子:

图1 用户态线程运行示例

需要注意的是,上面的代码,并没有使用操作系统为我们提供的 pthread 系列函数,thread_createthread_join 函数都是自己纯手工实现的。唯一使用操作系统的函数就是设置时钟,因此会有时钟信号产生,这一步是为了模拟时间片轮转算法而做的。

下面是图1 中的 demo 示例代码:

#include 
#include 
#include "thread.h"

void fun1() {
  int i = 10;
  while(i--) {
    printf("hello, I'm fun1\n");
    mysleep(2);
  }
}

void fun2() {
  int i = 10;
  while(i--) {
    printf("hello, I'm fun2\n");
    mysleep(1);
  }
}

void fun3() {
  int i = 2;
  while(i--) {
    printf("hello, I'm fun3\n");
    mysleep(5);
  }
}

void fun4() {
  int i = 15;
  int m;
  int n;
  while(i--) {
    printf("hello, I'm fun4\n");
    for (m = 0; m < 10000; ++m)
      for (n = 0; n < 10000; ++n);
  }
}

int main() {

  int tid1, tid2, tid3, tid4;
  thread_create(&tid1, fun1);
  printf("create thread %d\n", tid1);
  thread_create(&tid2, fun2);
  printf("create thread %d\n", tid2);
  thread_create(&tid3, fun3);
  printf("create thread %d\n", tid3);
  thread_create(&tid4, fun4);
  printf("create thread %d\n", tid4);

  int i = 2;
  while(i--) {
    printf("hello, I'm main\n");
    mysleep(3);
  }
  thread_join(tid1);
  thread_join(tid2);
  thread_join(tid3);
  thread_join(tid4);

  return 0;
}

1. 控制流切换原理

控制流,指的是一系列按顺序执行的指令。多控制流,是指存在两个或两个以上可以并发(宏观同时,微观不同时)执行的指令序列。比如你编写的多线程程序,每个线程就可以看成是一个控制流,多个线程允许多个控制流一起执行。

在我们学习编程的时候,如果不借助操作系统提供的线程框架,几乎无法完成多控制流的运行的。

接下来先来剖析一下,我们的指令如何”莫名奇妙“的就切换到其它线程的。

点我阅读原文。

你可能感兴趣的:(实现多线程切换与调度)