操作系统
面向进程和线程学习操作系统。
目录
| Chapter 1 | Chapter 2 | Chapter 3 | Chapter 4 | Chapter 5 | 
|---|---|---|---|---|
| 进程线程模型 | 进程间通信 | 同步互斥机制 | 存储管理 | 网络I/O模型 | 
内容
进程线程模型
线程和进程的概念已经在操作系统书中被翻来覆去讲了很多遍。很多概念虽然都是套话,但没能理解透其中深意会导致很多内容理解不清晰。对于进程和线程的理解和把握可以说基本奠定了对系统的认知和把控能力。其核心意义绝不仅仅是“线程是调度的基本单位,进程是资源分配的基本单位”这么简单。
多线程
我们这里讨论的是用户态的多线程模型,同一个进程内部有多个线程,所有的线程共享同一个进程的内存空间,进程中定义的全局变量会被虽有的线程共享,比如有全局变量int i = 10,这一进程中所有并发运行的线程都可以读取和修改这个i的值,而多个线程被CPU调度的顺序又是不可控的,所以对临界资源的访问尤其需要注意安全。我们必须知道,做一次简单的i = i + 1在计算机中并不是原子操作,涉及内存取数,计算和写入内存几个环节,而线程的切换有可能发生在上述任何一个环节中间,所以不同的操作顺序很有可能带来意想不到的结果。
但是,虽然线程在安全性方面会引入许多新挑战,但是线程带来的好处也是有目共睹的。首先,原先顺序执行的程序(暂时不考虑多进程)可以被拆分成几个独立的逻辑流,这些逻辑流可以独立完成一些任务(最好这些任务是不相关的)。比如QQ可以一个线程处理聊天一个线程处理上传文件,两个线程互不干涉,在用户看来是同步在执行两个任务,试想如果线性完成这个任务的话,在数据传输完成之前用户聊天被一直阻塞会是多么尴尬的情况。
对于线程,我认为弄清以下两点非常重要:
-     
线程之间有无先后访问顺序(线程依赖关系)
 -     
多个线程共享访问同一变量(同步互斥问题)
 
另外,我们通常只会去说同一进程的多个线程共享进程的资源,但是每个线程特有的部分却很少提及,除了标识线程的tid,每个线程还有自己独立的栈空间,线程彼此之间是无法访问其他线程栈上内容的。而作为处理机调度的最小单位,线程调度只需要保存线程栈、寄存器数据和PC即可,相比进程切换开销要小很多。
线程相关接口不少,主要需要了解各个参数意义和返回值意义。
-     
线程创建和结束
-         
背景知识:
在一个文件内的多个函数通常都是按照main函数中出现的顺序来执行,但是在分时系统下,我们可以让每个函数都作为一个逻辑流并发执行,最简单的方式就是采用多线程策略。在main函数中调用多线程接口创建线程,每个线程对应特定的函数(操作),这样就可以不按照main函数中各个函数出现的顺序来执行,避免了忙等的情况。线程基本操作的接口如下。
 -         
相关接口:
-             
创建线程:int pthread_create(pthread_t pthread, const pthread_attr_t attr, void (start_routine)(void ), void agr);
创建一个新线程,pthread和start_routine不可或缺,分别用于标识线程和执行体入口,其他可以填NULL。
-                 
pthread:用来返回线程的tid,*pthread值即为tid,类型pthread_t == unsigned long int。
 -                 
attr:指向线程属性结构体的指针,用于改变所创线程的属性,填NULL使用默认值。
 -                 
start_routine:线程执行函数的首地址,传入函数指针。
 -                 
arg:通过地址传递来传递函数参数,这里是无符号类型指针,可以传任意类型变量的地址,在被传入函数中先强制类型转换成所需类型即可。
 
 -                 
 -             
获得线程ID:pthread_t pthread_self();
调用时,会打印线程ID。
 -             
等待线程结束:int pthread_join(pthread_t tid, void** retval);
主线程调用,等待子线程退出并回收其资源,类似于进程中wait/waitpid回收僵尸进程,调用pthread_join的线程会被阻塞。
-                 
tid:创建线程时通过指针得到tid值。
 -                 
retval:指向返回值的指针。
 
 -                 
 -             
结束线程:pthread_exit(void *retval);
子线程执行,用来结束当前线程并通过retval传递返回值,该返回值可通过pthread_join获得。
- retval:同上。
 
 -             
分离线程:int pthread_detach(pthread_t tid);
主线程、子线程均可调用。主线程中pthread_detach(tid),子线程中pthread_detach(pthread_self()),调用后和主线程分离,子线程结束时自己立即回收资源。
- tid:同上。
 
 
 -             
 
 -         
 -     
线程属性值修改
-         
背景知识:
线程属性对象类型为pthread_attr_t,结构体定义如下:
```C++typedef struct{ int etachstate; // 线程分离的状态 int schedpolicy; // 线程调度策略 struct sched_param schedparam; // 线程的调度参数 int inheritsched; // 线程的继承性 int scope; // 线程的作用域 // 以下为线程栈的设置 size_t guardsize; // 线程栈末尾警戒缓冲大小 int stackaddr_set; // 线程的栈设置 
 -         
 
