进程
- 1. 获取进程信息---进程时间 times() / clock()
- 2. 进程 的概念
- 2.1 进程号---getpid() / getppid() / getpgid() / getpgrp() / setpgid() / setpgrp() / getsid() / setsid()
- 2.2 进程的 环境变量---getenv() / putenv() / setenv() / unsetenv() / clearenv()
- 2.3 进程的内存布局
- 2.4 进程的操作---fork() / vfork() / wait() / waitpid() / waitid() / execve() / execl() / execlp() / execle() / execv() / execvp() / execvpe() / system()
- 2.5 孤儿进程 、 僵尸进程 和 守护进程
- 2.6 进程状态与进程关系
- 3. 进程间通信
- 3.1 信号
- 3.1.1 信号的操作 signal() / sigaction() / kill() / killpg() / raise() / alarm() / pause() / sigpending() / sigqueue() / abort()
- 3.1.2 信号掩码(阻塞信号传递)---sigprocmask()
- 3.1.3 阻塞等待信号---sigsuspend()
- 3.2 管道
- 3.2.1 管道的操作---pipe() / mkfifo()
- 3.3 消息队列
- 3.3.1 消息队列的操作---msgget() / msgsnd() / msgrcv() / msgctl()
- 3.4 信号量
- 3.4.1 信号量的操作---semget() / semop() / semctl() / sem_open() / sem_wait() / sem_trywait() / sem_post() / sem_close() / sem_unlink() / sem_init() / sem_destroy()
- 3.5 共享内存
- 3.5.1 共享内存的操作---shmget() / shmat() / shmdt() / shmctl()
- 4. POSIX 互斥锁
- 4.1 互斥锁 的操作---pthread_mutex_init() / pthread_mutex_lock() / pthread_mutex_trylock() / pthread_mutex_unlock() / pthread_mutex_destroy()
1. 获取进程信息—进程时间times() / clock()
进程时间=用户CPU时间+系统CPU时间
#include<sys/times.h>#include<time.h>clock_ttimes(structtms*buf);// 系统调用,用于获取当前进程时间clock_tclock(void);// C库,用于获取当前进程时间(不能获取到单独的用户CPU时间和系统CPU时间)
2.进程的概念
2.1进程号—getpid() / getppid() / getpgid() / getpgrp() / setpgid() / setpgrp() / getsid() / setsid()
#include<sys/types.h>#include<unistd.h>pid_tgetpid(void);//系统调用,用来获取本进程的进程号pid_tgetppid(void);//系统调用,用来获取父进程的进程号pid_tgetpgid(pid_tpid);//系统调用,用来获取进程对应的进程组IDpid_tgetpgrp(void);//系统调用,用来获取进程对应的进程组IDintsetpgid(pid_tpid,pid_tpgid);//系统调用,用来加入一个现有的进程组或创建一个新的进程组intsetpgrp(void);//系统调用,用来加入一个现有的进程组或创建一个新的进程组pid_tgetsid(pid_tpid);//系统调用,用来获取进程的会话IDpid_tsetsid(void);//系统调用,用来创建一个会话
2.2 进程的环境变量—getenv() / putenv() / setenv() / unsetenv() / clearenv()
#include<stdlib.h>char*getenv(constchar*name);//C库,用于获取指定环境变量(不应该去修改其返回的字符串,修改该字符串意味着修改了环境变量对应的值)intputenv(char*string);//C库,用于向进程的环境变量数组中添加一个新的环境变量,或者修改一个已经存在的环境变量对应的值intsetenv(constchar*name,constchar*value,intoverwrite);//C库,用于向进程的环境变量列表中添加一个新的环境变量,或者修改一个已经存在的环境变量对应的值intunsetenv(constchar*name);// C库,用于从环境变量表(environ)中移除参数name标识的环境变量intclearenv(void);// C库,用于清除环境变量表中的所有变量,然后再进行重建(也可以通过将全局变量environ赋值为 NULL 来清空所有变量)
2.3 进程的内存布局
2.4 进程的操作—fork() / vfork() / wait() / waitpid() / waitid() / execve() / execl() / execlp() / execle() / execv() / execvp() / execvpe() / system()
#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>pid_tfork(void);//系统调用,用于创建一个新的进程(子进程拷贝了父进程的数据段、堆、栈以及继承了父进程打开的文件描述符,父进程与子进程并不共享存储空间,但是共享代码段,每个进程均可修改各自的栈数据以及堆段中的变量,而并不影响另一个进程)pid_tvfork(void);//系统调用,与 fork()函数在功能上是相同的,但其效率要高于fork()函数(为子进程立即执行 exec()新的程序而专门设计的)pid_twait(int*status);//系统调用,用于等待进程的任一子进程终止,同时获取子进程的终止状态信息,最后回收子进程的一些资源pid_twaitpid(pid_tpid,int*status,intoptions);//系统调用,功能同 wait() 一样,只是突破了 wait() 函数的限制WIFEXITED(status)//如果子进程正常终止,则返回trueWEXITSTATUS(status)//返回子进程退出状态,是一个数值,其实就是子进程调用_exit()或exit()时指定的退出状态WIFSIGNALED(status)//如果子进程被信号终止,则返回trueWTERMSIG(status)//返回导致子进程终止的信号编号WCOREDUMP(status)//如果子进程终止时产生了核心转储文件,则返回trueintwaitid(idtype_tidtype,id_tid,siginfo_t*infop,intoptions);//系统调用,与 waitpid() 类似,不过waitid()提供了更多的扩展功能intexecve(constchar*filename,char*constargv[],char*constenvp[]);//系统调用,将一个外部的可执行文件加载到进程的内存空间运行,使用新的程序替换旧的程序,而进程的栈、数据、以及堆数据会被新程序的相应部件所替换,然后从新程序的main()函数开始执行intexecl(constchar*path,constchar*arg,...);// C库,基于系统调用execve()而实现的intexeclp(constchar*file,constchar*arg,...);// C库,基于系统调用execve()而实现的intexecle(constchar*path,constchar*arg,...);// C库,基于系统调用execve()而实现的intexecv(constchar*path,char*constargv[]);// C库,基于系统调用execve()而实现的intexecvp(constchar*file,char*constargv[]);// C库,基于系统调用execve()而实现的intexecvpe(constchar*file,char*constargv[],char*constenvp[]);// C库,基于系统调用execve()而实现的intsystem(constchar*command);// C库,可以在程序当中执行任意shell命令(system()函数其内部的是通过调用fork()、execl()以及 waitpid()这三个函数来实现它的功能,首先system()会调用fork()创建一个子进程来运行shell(可以把这个子进程成为shell进程),并通过shell执行参数command所指定的命令)
子进程调用
_exit退出,父进程调用exit退出,否则会导致对父进程 stdio 缓冲区的刷新和关闭exit()函数会执行的动作如下:
- 如果程序中注册了进程终止处理函数,那么会调用终止处理函数
- 刷新stdio流缓冲区
- 执行
_exit()系统调用
2.5孤儿进程、僵尸进程和守护进程
2.6 进程状态与进程关系
Linux 系统下进程通常存在6种不同的状态:就绪态、运行态、僵尸态、可中断睡眠状态(浅度睡眠)、不可中断睡眠状态(深度睡眠)以及暂停态
进程间存在着多种不同的关系:无关系(相互独立)、父子进程关系、进程组以及会话
3.进程间通信
进程间通信的机制有:信号、管道、消息队列、信号量、共享内存、套接字Socket
3.1 信号
3.1.1 信号的操作 signal() / sigaction() / kill() / killpg() / raise() / alarm() / pause() / sigpending() / sigqueue() / abort()
#include<signal.h>#include<sys/types.h>#include<unistd.h>#include<stdlib.h>sig_tsignal(intsignum,sig_thandler);// 系统调用,用于将信号的处理方式设置为捕获信号、忽略信号以及系统默认操作intsigaction(intsignum,conststructsigaction*act,structsigaction*oldact);// 系统调用,允许单独获取信号的处理函数而不是设置,并且还可以设置各种属性对调用信号处理函数时的行为施以更加精准的控制intkill(pid_tpid,intsig);//系统调用,用于将信号发送给指定的进程或进程组中的每一个进程intkillpg(intpgrp,intsig);//系统调用,用于向整个进程组发送信号intraise(intsig);//C库,用于向自身发送信号intsigqueue(pid_tpid,intsig,constunionsigval value);//系统调用,用于向另一个进程发送实时信号unsignedintalarm(unsignedintseconds);//系统调用,用于设置一个定时器(闹钟),当定时器定时时间到时,内核会向进程发送 SIGALRM 信号intpause(void);//系统调用,用于进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止,只有执行了信号处理函数并从其返回时,pause()才返回intsigpending(sigset_t*set);//系统调用,用于查询进程中处于等待状态的信号voidabort(void);//C库,通常产生SIGABRT信号来终止调用该函数的进程,SIGABRT信号的系统默认操作是终止进程运行、并生成核心转储文件
3.1.2 信号掩码(阻塞信号传递)—sigprocmask()
#include<signal.h>intsigprocmask(inthow,constsigset_t*set,sigset_t*oldset);//系统调用,用于向信号掩码中添加 / 移除信号
3.1.3 阻塞等待信号—sigsuspend()
#include<signal.h>intsigsuspend(constsigset_t*mask);//系统调用,用于将进程的信号掩码设置为参数mask所指向的信号集,然后挂起进程,直到捕获到信号被唤醒(如果捕获的信号是mask信号集中的成员,将不会唤醒、继续挂起)、并从信号处理函数返回,一旦从信号处理函数返回,sigsuspend()会将进程的信号掩码恢复成调用前的值。
3.2管道
管道分两种类型:匿名管道(普通管道pipe、流管道s_pipe)、有名管道
3.2.1 管道的操作—pipe() / mkfifo()
#include<fcntl.h>#include<unistd.h>intpipe(intpipefd[2]);//系统调用,用于创建一个匿名管道(数组pipefd是用于返回两个引用管道末端的文件描述符,pipefd[0]指管道的读取端,pipefd[1]指向管道的写端)intmkfifo(constchar*pathname,mode_tmode);//系统调用,用于创建一个有名管道
3.3消息队列
3.3.1 消息队列的操作—msgget() / msgsnd() / msgrcv() / msgctl()
#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>intmsgget(key_tkey,intmsgflg);//系统调用,用于创建或获取一个消息队列对象,并返回消息队列标识符intmsgsnd(intmsqid,constvoid*msgp,size_tmsgsz,intmsgflg);//系统调用,用于将消息写入到消息队列,俗称发送一个消息ssize_tmsgrcv(intmsqid,void*msgp,size_tmsgsz,longmsgtyp,intmsgflg);//系统调用,用于从标识符为 msqid 的消息队列读取消息并将消息存储到 msgp中,读取后把此消息从消息队列中删除,也就是俗话说的接收消息intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);//系统调用,用于操作消息队列,比如设置或者获取消息队列的相关属性
3.4信号量
信号量可分为:IPC信号量、POSIX信号量(无名信号量、有名信号量)
3.4.1 信号量的操作—semget() / semop() / semctl() / sem_open() / sem_wait() / sem_trywait() / sem_post() / sem_close() / sem_unlink() / sem_init() / sem_destroy()
//IPC信号量#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>intsemget(key_tkey,intnsems,intsemflg);//系统调用,用于创建或者获取一个已经创建的信号量,如果成功则返回对应的信号量标识符,失败则返回-1intsemop(intsemid,structsembuf*sops,size_tnsops);//系统调用,用于对信号量进行 PV 操作intsemctl(intsemid,intsemnum,intcmd,...);//系统调用,用于对信号量集的一系列控制操作,根据操作命令cmd的不同,执行不同的操作//POSIX信号量---有名信号量#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>sem_t*sem_open(constchar*name,intoflag,mode_tmode,unsignedintvalue);//系统调用,用于打开/创建一个有名信号量intsem_wait(sem_t*sem);//系统调用,用于等待(获取)信号量,相当于P操作intsem_trywait(sem_t*sem);//系统调用,用于等待(获取)信号量,相当于P操作,如果指定信号量的计数器为0,那么直接返回 EAGAIN 错误,而不是阻塞等待intsem_post(sem_t*sem);//系统调用,用于释放信号量,相当于V操作intsem_close(sem_t*sem);//系统调用,用于关闭一个信号量,这表示当前进程/线程取消对信号量的使用,它的作用仅在当前进程/线程,其他进程/线程依然可以使用该信号量,同时当进程结束的时候,无论是正常退出还是信号中断退出的进程,内核都会主动调用该函数去关闭进程使用的信号量,即使从此以后都没有其他进程/线程在使用这个信号量了,内核也会维持这个信号量intsem_unlink(constchar*name);//系统调用,用于主动删除一个信号量,直接删除指定名字的信号量文件//POSIX信号量---无名信号量#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>intsem_init(sem_t*sem,intpshared,unsignedintvalue);//系统调用,用于初始化信号量(不要对已初始化的信号量再做 sem_init 操作,会发生不可预知的问题)intsem_destroy(sem_t*sem);//系统调用,用于销毁信号量,其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy() 函数销毁intsem_wait(sem_t*sem);//系统调用,用于等待(获取)信号量,相当于P操作intsem_trywait(sem_t*sem);//系统调用,用于等待(获取)信号量,相当于P操作,如果指定信号量的计数器为0,那么直接返回 EAGAIN 错误,而不是阻塞等待intsem_post(sem_t*sem);//系统调用,用于释放信号量,相当于V操作
3.5共享内存
3.5.1 共享内存的操作—shmget() / shmat() / shmdt() / shmctl()
#include<sys/ipc.h>#include<sys/shm.h>intshmget(key_tkey,size_tsize,intshmflg);//系统调用,用于创建或获取一个共享内存对象,并返回共享内存标识符void*shmat(intshmid,constvoid*shmaddr,intshmflg);//系统调用,用于把共享内存区对象映射到调用进程的地址空间,调用成功后返回共享内存的起始地址intshmdt(constvoid*shmaddr);//系统调用,用于解除进程与共享内存之间的映射的,在解除映射后,该进程不能再访问这个共享内存(该函数并不删除所指定的共享内存区,而只是将先前用shmat()函数映射好的共享内存脱离当前进程,共享内存还是存在于物理内存中)intshmctl(intshmid,intcmd,structshmid_ds*buf);//系统调用,用于获取或者设置共享内存的相关属性
4. POSIX互斥锁
线程与线程间同步,信号量是更好的选择;互斥锁更多的是用于保护资源的互斥
4.1互斥锁的操作—pthread_mutex_init() / pthread_mutex_lock() / pthread_mutex_trylock() / pthread_mutex_unlock() / pthread_mutex_destroy()
pthread_mutex_tfastmutex=PTHREAD_MUTEX_INITIALIZER;// 静态初始化,表示默认的互斥锁,即快速互斥锁(互斥锁被线程1持有时,此时互斥锁处于闭锁状态,当线程2尝试获取互斥锁,那么线程2将会阻塞直至持有互斥锁的线程1解锁为止)pthread_mutex_trecmutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;// 静态初始化,递归互斥锁(互斥锁被线程1持有时,线程2尝试获取互斥锁,将无法获取成功,并且阻塞等待,而如果是线程1尝试再次获取互斥锁时,将获取成功,并且持有互斥锁的次数加1)pthread_mutex_terrchkmutex=PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;// 静态初始化,检错互斥锁(这是快速互斥锁的非阻塞版本,它会立即返回一个错误代码(线程不会阻塞))intpthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t*mutexattr);//动态初始化intpthread_mutex_lock(pthread_mutex_t*mutex);//获得访问临界资源的权限,如果已经有其他线程锁住互斥锁,那么该函数会使线程阻塞直到该互斥锁解锁为止intpthread_mutex_trylock(pthread_mutex_t*mutex);//获得访问临界资源的权限,如果已经有其他线程锁住互斥锁,它不会阻塞当前线程,如果互斥锁已被占用,它会立马返回一个 EBUSY 错误intpthread_mutex_unlock(pthread_mutex_t*mutex);//释放占用的互斥锁,以便系统其他线程有机会获取互斥锁,访问该资源intpthread_mutex_destroy(pthread_mutex_t*mutex);//用于销毁一个互斥锁,当互斥锁不再使用时,可以用它来销毁