一、进程
- 进程:程序运行的过程。一个程序可以有多个进程。进程是操作系统调度的基本单位,以及内存资源等分配的基本单位。
- 操作系统的一个重要功能,即任务调度(进程管理)。
- 操作系统的调度:让CPU可以“同时”进行多个进程。
- tcb:进程调度控制块:存储有进程的属性,暂停时,CPU寄存器值, 程序指针、内存映射关系、打开的文件……
- 程序与进程:
- 程序:是静态的,存放于磁盘的代码文件。只有本地的数据。
- 进程:是动态的,是程序的一次运行。包含有系统的数据。
- 进程的ID(PID):用于计算机系统识别一个进程,是系统对进程的编号,PID动态分配,且不重名。
- 进程的产生:一个进程是由另一个进程创建的,第一个进程是由系统内核创建的。
- 父进程与子进程:创建进程的进程称为父进程,被创建的进程称为子进程。
- 进程的分类:
- 交互进程:a.out、qq、应用
- 批处理进程:shell脚本
- 守护进程(后台/服务进程):
- 进程的状态:
- 就绪态:进程的所有资源已经准备就绪,随时可以运行。
- 执行态(运行态):获得了CPU,正在运行。
- 等待态(阻塞态):等待需要的数据或状态信号等,条件满足才能执行。
- 暂停态:收到暂停信号。
- 僵尸态:进程的代码已经执行完了,或收到了结束信号,但资源还未回收。
- Linux中进程状态的表示:
状态表示 | 描述 |
---|---|
D | 不可中断 |
R | 正在运行,或在队列中的进程 |
S | 处于休眠状态 |
T | 停止或被追踪 |
Z | 僵尸进程 |
X | 死掉的进程 |
- Linux中对进程的操作命令:
命令 | 描述 |
---|---|
ps | 查看系统中的进程:ps -aux |
top | 动态显示系统中的进程 |
nice | 按用户指定的优先级运行进程 |
renice | 改变正在运行进程的优先级 |
kill | 结束进程:kill -9 PID |
bg | 将挂起的进程在后台执行 |
fg | 把后台运行的进程放到前台运行 |
- 进程的创建(fork();):
- 头文件:#include <unistd.h>
- 函数原型:pid_t fork(void);
- 返回值:在父进程中fork返回值为子进程的PID,在子进程中fork的返回值为0。
- 父子进程的关系:子进程是父进程的副本,当fork执行时,子进程刚被创建,父子进程中的“内容”完全一致。内容包含已经定义的变量的初始值、打开的文件描述符、输入输出缓冲等打开的流以及流里面的内容都是一致的,唯有PID不同。一旦子进程创建完毕,则父子进程互相独立都参与调度,fork完成后,父进程随机先后运行。
- 获取进程PID:getpid()。
- 获取父进程PID:getppid()。
- 结束进程:结束当前进程。
- 头文件:#include <stdlib.h>
- 函数原型:
- exit();——结束前会刷新缓冲,关闭流
- _exit();——强制结束,不会刷新缓冲,以及关闭流
- 父进程等待子进程结束:用于处理子进程的僵尸态。
- wait();——阻塞等待子进程结束,获得子进程的结束状态。
- waitpid();——可以设置阻塞或非阻塞方式等待,指定子进程或所有子进程结束。
- 头文件:
- #include <sys/types.h>
- #include <sys/wait.h>
- 函数原型:
- pid_t wait(int *status);
- pid_t waitpid(pid_t pid, int *status,int options);
- 参数列表:
- pid:
- < -1:等待子进程,其组ID == |pid|
- == -1:等待任意子进程
- == 0:等待子进程,其组ID与父进程同一个组
- > 0:等待子进程,其PID == pid;
- status:用于接收子进程结束时的状态
- options:
- WNOHANG:非阻塞模式
- == 0:阻塞等待
- pid:
- 返回值:等待到的结束的子进程的PID。
- exec函数族:用于执行新的程序,形成进程,替换当前进程中的所有内容。主要使用在程序中调用shell命令。
- 头文件:#include <unistd.h>
- 函数原型:
- int execl(const char *path, const char *arg,…);
- int execlp(const char *file, const char *arg,…);
- int execle(const char *path, const char *arg,…,char * const envp[]);
- int execv(const char *path, char *const argv[]);
- int execvp(const char *file, char *const argv[]);
- int execvpe(const char *file, char *const argv[], char *const envp[]);
- 参数列表:
- path:外部命令的路径。
- arg:外部命令的启动方式。
- …:外部命令的选项及参数。
- argv:外部命令执行的参数列表是一个字符串指针数组。
- system():
- 头文件:#include <std
- 函数原型:int system(const char *command)
- 参数列表:
- command:命令字符串
- 守护进程:后台的日供服务的进程,没有终端,生命周期长,一般从开机运行到关机结束。例如:杀毒进程、网络服务器等。
- 会话:表示由同一个终端产生的进程,通常在一个会话中,终端关闭时,回想该会话中的所有其他进程发送杀死信号。
- 守护进程的创建:
- 创建子进程,杀死父进程
- 在子进程中创建新会话:setsid();
- 头文件:#include <unistf.h>
- 函数原型:pid_t setsid(void);
- 重设文件权限掩码为0:umask();
- 头文件:
- #include <sys/types.h>
- #include <sys/stat.h>
- 函数原型:mode_t umask(mode_t mask);
- 头文件:
- 修改工作目录为根目录:chdir();
- 头文件:#include <unstd.h>
- 函数原型:int chdir(const char *path);
- 关闭不需要的文件描述符:close();
二、线程
- 线程:是一种轻量级的进程。与进程同样参与调度。
- 进程与线程的对比:
- 进程的创建所需要的系统资源比较大。
- 进程间是完全独立的,通信不便。
- 线程共享同一进程的内存空间。
- 其全局变量,打开的文件描述符等是共享的。
- 每个线程的局部变量栈区是独立的。
- 线程的创建方式、程序运行的起点不同。
- 线程是依附于进程而存在的,若main进程退出则所有创建的线程都将结束。
-
相关线程函数:由第三方库地宫:#include <pthread.h>,编译时,添加编译选项-lpthread
- 线程创建函数:
- 头文件:#include <pthread.h>
- 函数原型:
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
- 参数列表:
- thread:线程tid容器,用于存放创建的线程的tid。
- atrr:线程属性配置容器,通常使用NULL,使用默认属性。
- void *(*start_routine) (void *):一个函数指针,指向线程函数指针,线程函数类型:void * threadFunc(void *);
- arg:用于提供给线程函数的参数。线程参数传递:全局变量传参,存在参数传递异常(不推荐)。因此需要用到此方法。
- 先定义参数传递类型,传递其指针,作为参数。
- 返回值:
- == 0:创建成功。
- != 0:创建失败。
- 结束线程:
- 函数原型:void pthread_exit(void *retval);
- 返回值:return 线程函数
- 等待线程结束:等待其他线程结束,可以用于获取线程结束的返回值,可以回收线程结束后的资源。
- 函数原型:int pthread_join(pthread_t thread,void **retval);
- 参数列表:
- thread:要等待结束的线程id
- retval:指针容器,用于存放线程结束时,返回的指针。
- 结束其他线程:
- 函数原型:int pthread_cancel(pthread_t thread);
- 线程分离:不关心其返回值,线程结束后由系统自动回收清理
- 函数原型:int pthread_detach(pthread_t thread);
-
线程的可重入问题:形容一个函数若每次调用函数时,其运行结果只与传入的参数有关,同样的参数,一定得到同样的结果,称这种函数课重入的函数,也称线程安全函数。函数中使用了全局变量、静态变量,都导致函数不可重入。
-
线程同步互斥:
-
同步:线程间的配合,需要按一定的顺序执行时,需要进行同步。
-
信号量:用于指示某种资源的数量。
-
释放信号:对应的资源数量增加++
-
获取信号:对应的资源数量减少–
-
线程信号量API接口:#include <semaphore.h>
- 初始化信号量:
- 函数原型:int sem_init(sem_t *sem,int pshared, unsigened int value);
- 参数列表:
- sem:信号量容器
- pshared:信号量共享的范围(0:线程间使用,非0:进程间使用)
- value:信号量初始值。
- 返回值:
- 0:成功
- -1:perror
- 释放信号量:信号量++
- 函数原型:int sem_post(sem_t *sem);
- 获取信号量:信号量–
- 函数原型:
- 阻塞方式等待信号量:int sem_wait(sem_t *sem);
- 非阻塞方式等待信号量:int sem_trywait(sem_t *sem);
- 非阻塞方式等待信号量,超时退出:int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- 查询信号量的值,而不消费:int sem_getvalue(sem_t *sem, int *sval);
-
-
互斥:是指多个线程同时访问公共资源,为保护公共资源的完整性,提出互斥锁概念。
- 互斥API接口:#include <pthread.h>
- 初始化锁:
- 函数原型:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
- 上锁:阻塞等待,若锁可用,则上锁,若锁不可用,阻塞等待.
- 函数原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
- 尝试上锁:非阻塞模式,若锁可用,则上锁;若锁不可用,阻塞等待。
- 函数原型:int pthread_mutex_trylock(pthread_mutex_t *mutex);
- 解锁:释放锁,开锁。
- 函数原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 销毁锁:
- 函数原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);