Linux 进程、线程和信号


进程

获取进程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后,再去申请2时失败,要及时释放1.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值