系统调用函数
克隆进程-fork()
原型:
__pid_t fork()
头文件:unistd.h
参数:无
返回值:有三种不同的返回值。对于被克隆的进程返回克隆的进程ID。对于克隆的进程返回0。出错返回-1
作用:用于创建一个新进程。直接克隆一个与原进程完全相同的进程,从代码同一位置继续运行。
特性:fork出的进程与原进程是异步并发执行的。
pid_t id = fork();
if (id == 0) {
//新进程要执行的逻辑
} else {
//父进程/原进程要执行的逻辑
}
捕获信号-signal()
原型:
__sighandler_t signal(int signum, sighandler_t handler)
头文件:signal.h
参数:
signum要捕获的信号,这里要接收的和后面发送的信号相同即可(详见信号)
handler处理器 传入要处理该事件的函数引用
返回值:成功调用会返回处理器的返回值,不成功返回-1
作用:捕获一个信号,并用已定义的处理器进行处理
特性:可以唤醒处于paues挂起的进程
void run() {
//运行逻辑
}
int main(){
signal(SIGRTMIN, &run);
}
进程休眠-sleep()
原型:
unsigned int sleep(unsigned int __seconds)
int usleep(__useconds_t __useconds)
头文件:unistd.h
参数:
__seconds要休眠的秒数
__useconds要休眠的毫秒数
返回值:剩余秒数
作用:令进程暂停一段时间,直到到达指定时间,或者被中断
usleep(300000);
得到进程id-getpid()
原型:
__pid_t getpid()
__pid_t getppid()
头文件:unistd.h
参数:无
返回值:
getpid返回当前进程id
getppid返回父进程id
printf("线程%d正在运行\n", getpid());
进程暂停-pause()
原型:
int pause()
头文件:unistd.h
返回值:只返回-1
作用:令当前进程进入休眠状态,直到被信号唤醒
void toSleep() {
pause();
}
进程退出-_exit()
原型:
void _exit (int __status)
头文件:unistd.h
参数:__status 状态码,可以设为NULL表示不关心子进程的退出状态
返回值:无
作用:停止进程的运行,并清除其使用的内存空间,以及在内核中的各种数据结构
特性:在进程通过该函数停止后,设置的状态码可以被wait/waitpid获得
void killSelf() {
_exit(3);
}
发送信号-kill()
原型:
int kill (__pid_t __pid, int __sig)
头文件:signal.h
参数:
__pid目的进程号
__sig信号值
返回值:成功返回0,失败返回-1
作用:给一个进程发送信号
特性:该信号可以被signal函数所捕获
void front() {
//对应前面的signal
kill(pid, SIGRTMIN);
}
等待进程退出-wait()
原型:
__pid_t wait (int *__stat_loc)
__pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options)
头文件:wait.h
参数:
__pid
> 0等待指定pid的子进程
= 0等待进程组码与目前进程相同的任何子进程
= -1等待任何一个子进程退出
< -1等待进程组码为指定pid绝对值的任何子进程
__stat_loc:要接收状态码的int的地址,若为NULL则不关心子进程退出状态
__options:对函数进行设置
WNOHANG若指定进程未结束,该函数则不会阻塞父进程,直接返回0
WUNTRACED若指定进程已被暂停,且其自暂停以来状态从未返回过,则立即返回其状态
0:阻塞父进程,等待子进程退出
返回值:
成功:返回结束的子进程的pid
失败:返回-1
若将__options设置为WNOHANG且没有子进程退出则返回0
作用:让父进程等待某一进程(wait)或等待指定进程(waitpid)退出,是否阻塞依照__options参数而定
注意:对于接收状态的__stat_loc参数,如果进程是正常退出,则正常得到状态码。若被信号杀死而退出,则返回的int中,状态码被存在低8位中,需要移位才可得到实际的状态码((t >> 8) & 0x7f)
void kill_() {
int t;
kill(pid, SIGTRAP);//搭配kill用
waitpid(pid, &t, 0);
printf("线程 %d 已经终结,退出码=>%d\n", pid, (t >> 8) & 0x7f);
}
重置进程-execve()
原型:
int execve (const char *__path, char *const __argv[], char *const __envp[])
头文件:unistd.h
参数:
__path 命令目录或可执行二进制文件目录
__argv[] 参数序列
__envp[] 环境变量
返回值:成功无返回值,失败返回-1
作用:执行一个新的程序或命令
注意:参数序列和环境变量数组需以NULL结尾
int main(){
pid_t pid = fork();//搭配fork用
//新进程
if (pid == 0) {
char ch = (char) (i + 48);
char *chars = {&ch};
char *argv[] = {"/tmp/a.out", chars, NULL};
char *envp[] = {NULL};
execve("/tmp/a.out", argv, envp);
} else {
//父进程/原进程
}
}
//a.out
int main(int narg, char **args) {
if (narg == 2) {
//如果有参数
char *mInt = args[1];
i = mInt[0] - 48;
} else {
//如果无参数
i = 0;
}
}
创建信号量-semget()
原型:
int semget (key_t __key, int __nsems, int __semflg)
头文件:sys/sem.h
参数:
__key 信号量键值,指定为 IPC_PRIVATE 时会创建新的信号量集对象
__nsems 信号量集中信号量的个数,通常为1
__semflg 设置为 0 获得信号量集标识符
设置为 -1 | IPC_CREAT 时创建新信号量集
返回值:成功时返回该信号量集的标识符,失败返回-1
作用:创建信号量集并返回其标识符,或得到一个信号量集标识符
//简单创建一个信号量集
int semid = semget(IPC_PRIVATE, 1, -1 | IPC_CREAT);
操作信号量-semctl()
原型:
int semctl (int __semid, int __semnum, int __cmd, …)
头文件:sys/sem.h
参数:
__semid 操作的信号量操作符,来自semget函数成功的返回值
__semnum 操作的信号量级数组的下标,一个信号量为0
__semnum 对该信号集要进行的操作,以下为部分形参
IPC_RMID 摧毁该信号量,无需第四个参数
GETVAL从信号量集中获取指定信号量,返回其值,无需第四个参数
SETVAL用联合体semun中的val值设置指定信号量的值
arg 第四个可选参数联合体semun
返回值:
成功调用返回0
cmd中的特殊操作返回大于0的特殊值
失败返回-1
作用:初始化信号量、获得信号量、摧毁信号量
union semun {
int val;
};
int main(){
int semidA = semget(IPC_PRIVATE, 1, -1 | IPC_CREAT);
semctl(semidA, 0, SETVAL, semun);
}
信号量PV操作-semop()
原型:
semop (int __semid, struct sembuf *__sops, size_t __nsops)
头文件:sys/sem.h
参数:
__semid 操作的信号量操作符,来自semget函数成功的返回值
__sops 操作控制信号量的结构体数组首地址sembuf
__nsops 进行操作信号量 的个数,一般为1
返回值:
成功操作返回信号集标识符
失败返回-1
作用:完成对信号量的P操作或V操作
int main(){
//先设置用于操作信号量的结构体
//P操作
struct sembuf PD;
PD.sem_num = 0;
PD.sem_op = -1;
PD.sem_flg = SEM_UNDO;
//V操作
struct sembuf VU;
VU.sem_num = 0;
VU.sem_op = 1;
VU.sem_flg = SEM_UNDO;
//对信号量集semidA进行操作
semop(semidA, &PD, 1);
semop(semidA, &VU, 1);
}
其他
获得真随机数
获得真随机的随机数(其实还是伪随机数)
time_t time (time_t *__timer)
头文件:time.h
参数:__timer 将获得的时间回写到__timer中
返回值:返回从1970-01-01 00:00:00到现在的秒数
注意:当参数为null时,直接返回秒数
void srand (unsigned int __seed)
头文件:stdlib.h
参数:__seed 种子
作用:随机数发生器,重置随机数
注意:参数如未设置,则默认为1
int rand (void)
头文件:stdlib.h
返回值:返回一个0-32767之间的随机数
Q:为什么会出现获得真随机数操作?
A:如果直接使用rand函数产生的数是固定的,一定会以一个固定的顺序出现“随机数”,比如:7,6,2,9,3,1,4,8…。无论启动多少次代码都是这个固定的序列。所以需要使用随机数发生器函数srand来重置随机数。问题又来了,随机数发生器的参数在代码中是人为指定的,所以最终产生的仍然是可预测的“随机数”。最终,时间time是不可预测的,将时间作为种子,这样产生的随机数才是真随机数。
//获得1-10之间的真随机数
int main(){
srand((unsigned int) time(NULL));
rand() % 10 + 1;
}
信号signal
联合体semun
被定义在linux/sem.h中,示例中自己创建了一个
union semun {
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/
unsigned short* array; /*SETALL、GETALL用的数组值*/
struct seminfo *buf; /*为控制IPC_INFO提供的缓存*/
} arg;
结构体sembuf
被定义在sys/sem.h头文件中,无需自己定义
struct sembuf {
unsigned short int sem_num; /* 信号量集中信号量的编号 */
short int sem_op; /* 该数值>0 进行V操作信号量值增加,表示进程释放控制的资源。该数值<0 进行P操作信号量值减少 =0 阻塞 */
short int sem_flg; /* 0 默认操作 IPC_NOWAIT设置信号量操作不等待 SEM_UNDO 内核记录进程调用操作*/
};