目录
相关概念
进程
- 进程是程序关于某数据集合上的一次活动,即正在执行的程序实例,指程序的整个运行过程而非代码。
- 在执行程序时,内核会为其分配空间,并记录与进程有关的各种信息。
- 进程是一个实体,内核必须在他们之间共享各种资源。
进程ID和父进程ID
- 进程可调用fork()来创建一个新进程,调用fork()的进程被称为父进程。
- 每一个进程都有一个进程标识符(PID)和父进程标识符(PPID),它们的数据类型是pid_t,其实就是整形,只是为了便于区分,看到pid_t就能明白为进程ID。
线程
- 每个进程可以执行多个线程,每个线程共享同一数据区域和堆,线程之间可以通过共享的全局变量进行通信
- 每个线程都拥有属于自己的栈,用来装载本地变量和函数调用信息
相关函数
查看进程ID函数getpid()和getppid()
- 两个函数都返回值均为pid_t类型。
- 可以在打开终端,输入pstree -p即可查看当前系统下所有的进程及id号。每个进程的父进程号属性反映了系统上所有进程间的树状关系。每个进程的父进程又有自己的父进程,以此类推,回溯到 1 号进程—init 进程,即所有进程的始祖。
创建进程fork()函数
- 调用fork()后将存在两个进程,子进程复制了父进程的内容,每个进程都会从fork()函数的返回处继续执行,两者不相互依赖,父进程结束,子进程也可继续执行。
- 两个进程执行相同的代码,但之间拥有独立内存,修改各自的数据,另一个不受影响。
- 函数通过返回值来区分父进程和子进程,父进程中fork()返回新建子进程的ID,子进程zhong则返回0。当无法创建子进程时,fork()返回-1。
如图所示用fork()函数创建了一个新进程,新进程也会从打印hello word开始,说明调用fork()之后存在两个进程,并且子进程复制了父进程的内容。但二者的内存单元是独立的,即使都为count变量,但二者相互不干扰。
监控子进程wait()函数
系统调用
wait()
等待调用进程的任一子进程终止,终止时函数返回该子进程ID,出错时返回-1,函数参数status代表子进程终止状态,如果不关心可以用NULL。
该程序创建了三个子进程1,2,3。每个子进程休眠若干秒后退出,创建所有的子进程之后,父进程循环调用wait()来监控子进程的终止,直到wait()返回-1时才退出循环。
创建线程pthread_create()函数
- 启动程序时,只有一条主线程,可以通过pthread_create()函数创建一条线程
pthread_t *thread:pthread_t表示线程的数据类型,该参数传递该类型的指针变量,或者传入变量的地址。
const pthread_attr_t *attr:该变量指向了新线程的各种属性,如果将attr设置为NULL,创建新线程将使用默认属性。
void *(*start)(void*):以函数指针的方式指明新建线程所要执行的函数,该函数形参和返回值均为void*,使用时注意类型转换。
void *arg:给start函数传入的参数,如果不需要传入参数,赋值NULL即可。
- 该程序创建了一个thread_function线程,每隔1S打印一次Hello world,打印次数由创建线程时传递。
- 用pthread_join函数检测线程的结束,如果结束返回0,不结束会一直等待,不用额外加判断语句。
- 在编译时需要加-pthread。
多个线程可以多次调用thread_function函数,以上程序创建两个程序。可以验证全局变量count在两个线程之间是相互共享的,而线程局部变量count1是在线程之间不共享的。