目录
进程
获取进程id
#include <unistd.h>
pid_t getpid(void); //获取当前进程id
pid_t getppid(void); //获取父进程id
返回值: 成功返回当前/父进程id。
/proc/PID 获取与进程相关的信息
cat /proc/1/status #获取init进程状态信息
uname() 获取主机系统的标识信息
#include <sys/utsname.h>
int uname(struct ustname* utsbuf);
//utsname数据结构
struct utsname {
char sysname[_UTSNAME_LENGTH];
char nodename[_UTSNAME_LENGTH];
char release[_UTSNAME_LENGTH];
char version[_UTSNAME_LENGTH];
char machine[_UTSNAME_LENGTH];
#ifdef _GUN_SOURCE
char domainname[_UTSNAME_LENGTH];
#endif
}
返回值: 成功返回0,失败返回-1。
fork() 创建子进程
#include <unistd.h>
pid_t fork(void);
返回值: 如果返回值大于0,表示进入父进程;如果返回值等于0,表示进入子进程中,如果返回值等于-1,表示创建失败。
wait() 阻塞等待子进程结束
#include <sys/wait.h>
pid_t wait(int* stauts);
pid_t waitpid(pid_t pid,int* status, int options);
int waitid(idtype_t idtype,id_t id,siginfo_t* infop,int options);
status: 返回进程的终止状态。
pid: 意义如下:
pid > 0 | 表示等待进程ID为pid的子进程 |
---|---|
pid = 0 | 表示等待与父进程同意个进程组的所有子进程 |
pid < -1 | 表示等待进程组标识与pid绝对值相等的所有子进程 |
pid = -1 | 表示等待任意子进程 |
options: 取值如下:
WUNTRACED | 除了返回终止进程的信息外,还返回因信号而停止的子进程信息 |
---|---|
WCONTINUED | 返回那些因收到SIGCONT信号而恢复执行的已停止子进程的状态信息 |
WNOHANG | 如果参数pid所指定的子进程并未 发生状态改变,则立即返回0.如果并无与pid匹配的子进程,则报错,错误号置为ECHILD。 |
返回值: 成功返回终止进程的id,失败返回-1。
守护进程、孤儿进程和僵尸进程
守护进程:就是服务,独立于终端以外,关闭终端之后,该进程任然存在。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
execve() 将新程序加载到某个进程空间
#include <unistd.h>
int execve(const char* pathname,char* const argv[],char* const envp[]);
int execle(const char* pathname,const char* arg,.../* ,(char*)NULL,char* const envp[] */);
int execlp(const char* filename,const char* arg,.../* ,(char*)NULL */);
int execvp(const char* filename,char* const argv[]);
int execv(const char* filename,char* const argv[]);
int execl(const char* filename,const char* arg,.../* ,(char*)NULL */);
pathname: 准备载入当前进程空间的新程序的路径名。
argv: 指定了传递给新进程的命令行参数。
envp: 指定了新进程的环境变量。
返回值: 成功不返回,失败返回EACCES、ENOENT、ENOEXEC等。
信号
信号四要素:
编号,名称,事件,默认处理动(终止,忽略,终止 + 产生core,暂停,继续)
信号的产生:内核产生,内核处理
信号产生方式:按键,硬件异常,函数、命令、定时器
信号状态:
产生
递达:信号到达且处理完成
未决:信号被阻塞了
信号的处理方式:
执行默认动作,忽略,捕捉
9,19号信息不能捕获,不能忽略,甚至不能阻塞
阻塞信号集(信号屏蔽字):将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,垓心号的处理将推后(解除屏蔽后)。
未决信号集:未决信号集中描述该信号的位立即翻转为1,表示该信号处于未决状态,当信号被处理对应位翻转回0,。这一时刻往往是短暂的。
signal() 改变信号处置
#include <signal.h>
void (*signal(int sig,void (*handler)(int))) (int);
sig: 标识希望修改的信号编号。
handler: 信号处理函数地址。
返回值: 失败返回SIG_ERR。
kill() 发送信号
#include <signal.h>
int kill(pid_t pid,int sig);
int raise(int sig); //向自身发送信号
int killpg(pid_t pgrp,int sig); //向某个进程组的所有成员发送一个信号
pid: 取值如下:
pid > 0 | 发送信号给由pid指定的进程 |
---|---|
pid = 0 | 发送信号给与当前进程同组的每个进程,包括当前进程自身 |
pid < -1 | 向组id等于pid绝对值的进程组内所有下属进程发送信号 |
pid = -1 | 向每个进程(除init和自身进程)发送信号 |
sig: 要发送的信号。
返回值: 成功返回0,失败返回-1。
sigemptyset() 、sigfillset() 初始化信号集
#include <signal.h>
int sigemptyset(sigset_t* set); //初始化一个空信号集
int sigfillset(sigset_t* set); //初始化一个包含所有信号的信号集
返回值: 成功返回0,失败返回-1。
sigaddset() 向信号集中添加一个信号
#include <signal.h>
int sigaddset(sigset_t* set, int sig);
返回值: 成功返回0,失败返回-1。
sigdelset() 删除信号集中一个信号
#include <signal.h>
int sigdelset(sigset_t* set, int sig);
返回值: 成功返回0,失败返回-1。
sigismember() 判断sig是不是信号集的成员
#include <signal.h>
int sigismember(const sigset_t* set, int sig);
返回值: 是返回1,不是返回0。
sigprocmask() 向信号掩码添加或一处信号
#include <signal.h>
int sigprocmask(int how,const sigset_t* set,sigset_t* oldset);
how: 指定该函数想改信号掩码带来的变化,取值如下:
SIG_BLOCK | 将set指向的信号集内的指定信号添加到信号掩码中 |
---|---|
SIG_UNBLOCK | 将set指向的信号集中的信号从信号掩码中移除 |
SIG_SETMASK | 将set指向的信号集赋给信号掩码 |
oldset: 如果oldset不为空,则其指向一个sigset结构缓冲区,用于返回之前的信号掩码。
返回值: 成功返回0,失败返回-1。
sigpending() 获取处于等待状态的信号集
#include <signal.h>
int sigpending(sigset_t* set);
返回值: 成功返回0,失败返回-1。
sigaction() 改变信号处置
#include <signal.h>
int sigaction(int sig,const struct sigaction* act,struct sigaction* oldact);
//sigaction数据结构
struct sigaction {
void (*sa_handler)(int); //处理函数地址
sigset_t sa_mask;
int sa_flags
void (*sa_restorer)(void);
}
sig: 想要获取或改变的信号编号。
act: 指向信号新处置的数据结构,如果仅对现有的信号感兴趣,可以将该参数设为NULL。
oldact: 返回之前信号处置的相关信息。
返回值: 成功返回0,失败返回-1。
pause() 暂停进程执行,直到信号处理函数中断该调用为止
#include <unistd.h>
int pause(void);
返回值: 永远返回-1,并将errno置为EINTR。
alarm() 定时给自己发送SIGNALRM信号(终止进程)
unsigned int alarm(unsigned int seconds)
seconds: 如果传入参数为0代表取消闹钟。
返回值: 成功返回上次闹钟剩余的秒数,失败返回-1。
setitimer() 周期性发送信号
int setitimer(int which, const struct itimerval* new_value,struct itimerval* old_value);
//
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
which: 发送什么信号。
new_value: 要设置的闹钟时间。
old_value: 原闹钟时间。
线程
每个线程都有自己的TCB
线程共享:1.全局数据区 2.堆区 3.一块有效内存地址
pthread_create() 创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg);
attr: 线程属性。
start: 入口函数地址。
arg: 线程执行函数的参数。
返回值: 成功返回0,失败返回大于0的数。
pthread_exit()
#include <pthread.h>
void pthread_exit(void *retval);
retval: 传出线程的退出信息。
pthread_self() 获取线程id
#include <pthread.h>
pthread_t pthread_self(void);
pthread_equal() 判断两个线程id是否相等
#include <pthread.h>
int pthread_equal(pthread_t t1,pthread_t t2);
pthread_join() 等待线程终止
#include <pthread.h>
int pthread_join (pthread_t thread, void **retval);
thread: 要回收线程的id。
retval: 传出线程的退出信息。
pthread_detach() 线程分离
#include <pthread.h>
int pthread_detach(pthread_t thread);
ptread_cancel() 取消线程
#include <pthread.h>
int pthread_cancel(pthread_t thread);
互斥量系列接口
//销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//初始化
int pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutex attr_t * attr);
//初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//加锁
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_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
//阻塞等待
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
//唤醒至少一个阻塞在条件变量上的线程
int pthread_cond_signal(pthread_cond_t *cond);
//唤醒阻塞在条件变量上的全部线程
int pthread_cond_broadcast(pthread_cond_t *cond);
死锁
- 锁了又锁,自己加了一次锁成功,又加了一次。程序员写代码时注意该问题即可。
- 交叉锁:一个资源加了两把锁,线程1,2各拥有其中一把,且互相想要获取对方的那把。
交叉锁解决方案:每个线程申请钥匙的顺序要一致。比如,只能先拿到1,再去拿2.如果申请到1后,再去申请2时失败,要及时释放1.