目录
目录
一、进程环境
1.虚拟地址空间
2.环境表
3.进程表项
4.跨函数跳转
5.进程资源限制
二.进程控制
1.属性
2.创建
3.终止
4.收尸
5.注册终止处理程序
6.替换
三.进程间通信
1.管道
2.xsi
四.守护进程
1.特点
2.创建
3.日志
4.单实例
五.进程间的关系
1.会话
2.进程组
3.进程
#include
#include
extern char **environ;
int main(int argc,char *argv[],char *environ[])
{
int i;
for(i=0;environ[i];i++)
puts(environ[i]);
exit(0);
}
#include
int setjmp(jmp_buf env);
setjmp 函数的功能是将函数在此处的上下文保存在 jmp_buf 结构体中,以供 longjmp 从此结构体中恢复。
void longjmp(jmp_buf env, int val);
longjmp 函数的功能是从 jmp_buf 结构体中恢复由 setjmp 函数保存的上下文,该函数不返回,而是从 setjmp 函数中返回。
#include
#include
#include
static jmp_buf env;
int div2num (int n1,int n2)
{
if(n2==0)
longjmp(env,1);//第二个参数随意,按1处理,longjmp带回的返回值
return n1/n2;
}
int main()
{
int n1,n2;
if(setjmp(env)==0)//规定第一次返回值为0
printf("请输入俩个整形变量值\n");
else
printf("请重新输入\n");
// if(setjmp(env)!=0)
// printf("跳转2");
scanf("%d%d",&n1,&n2);
printf("res:%d/%d=%d\n",n1,n2,div2num(n1,n2));
exit(0);
}
命令:ulimit -a
llj@llj-virtual-machine:~$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7641
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7641
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
函数:
#include
int getrlimit( int resource, struct rlimit *rlptr );//函数查询资源限制
int setrlimit( int resource, const struct rlimit *rlptr );//函数更改资源限制
//两个函数返回值:若成功则返回0,若出错则返回非0值
struct rlimit {
rlim_t rlim_cur; /* 当前限制 */
rlim_t rlim_max; /* 最大值 */
};
在更改资源限制时,须遵循下列三条规则
常量RLIM_INFINITY指定了一个无限量的限制。
这两个函数的resource参数取下列值之一:
RLIMIT_AS 进程可用存储区的最大总长度(字节)。这回影响sbrk函数和mmap函数。
RLIMIT_CORE core文件的最大字节数,若其值为0则阻止创建core文件。
RLIMIT_CPU CPU时间的最大量值(秒),当超过此软限制时,向该进程发送SIGXCPU信号。
RLIMIT_DATA 数据段的最大字节长度。这是初始化数据、非初始化数据以及堆的总和。
RLIMIT_FSIZE 可以创建的文件的最大字节长度。当超过此软限制时,则向该进程发送SIGXFSZ信号。
RLIMIT_LOCKS 一个进程可持有的文件锁的最大数(此数也包括Linux特有的文件租借数)。
RLIMIT_MEMLOCK 一个进程使用mlock(2)能够锁定在存储器中的最大字节长度。
RLIMIT_NOFILE 每个进程能打开的最大文件数。更改此限制将影响到sysconf函数在参数_SC_OPEN_MAX中的返回值。
RLIMIT_NPROC 每个实际用户ID可拥有的最大子进程数。更改此限制将影响到sysconf函数在参数_SC_CHILD_MAX中返回的值。
RLIMIT_RSS 最大驻内存集的字节长度(resident set size in bytes, RSS)。如果物理存储器供不应求,则内核将从进程处取回超过RSS的部分。
RLIMIT_SBSIZE 用户在任一给定时刻可以占用的套接字缓冲区的最大长度(字节)。(Linux 2.4.22不支持)
RLIMIT_STACK 栈的最大字节长度。
RLIMIT_VMEM 这是RLIMIT_AS的同义词。
fork
vfork
正常终止
异常终止
wait(NULL):为任意一个进程收尸
waitpid
#include
int on_exit(void (*function)(int , void *), void *arg);
#include
int atexit(void (*function)(void));
#include
#include
#include
#include
#include
#include
#include
#include
#include
void f1()
{
puts("f1() is working.");
}
void f2()
{
puts("f2() is working.");
}
void f3()
{
puts("f3() is working.");
}
int main()
{
puts("Begin!");
atexit(f1);
atexit(f2);
atexit(f3);
puts("End!");
exit(0);
}
/*执行结果
llj@llj-virtual-machine:~/teacherqin/coder210714/apue/sys$ ./atexit
Begin!
End!
f3() is working.
f2() is working.
f1() is working.
*/
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, 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[]);
#include
#include
#include
#include
#include
#include
int main()
{
printf("[%d]:begin!\n",getpid());
fflush(NULL);//解决缓存区带来的问题
pid_t pid;
pid=fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
//execl("/bin/ls","ls","-l",NULL);
//execlp("ls","ls","-l",NULL);
char *arr[]={"ls","-l",NULL};
//execv("/bin/ls",arr);
execvp("ls",arr);
//.............................替换功能,成功不返回,失败返回
perror("execl()");
exit(1);
}
wait(NULL);
exit(0);
}
匿名管道
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 128
static int mycpy(int fd1,int fd2);
int main(int argc,char *argv[])
{
int pfd[2];
pid_t pid;
int fd;
int cnt1,cnt2;
int err,err2;
char buf1[BUFSIZE];
char buf2[BUFSIZE];
if(pipe(pfd) == -1)
{
perror("pipe()");
exit(1);
}
pid=fork();
if(pid == -1)
{
perror("fork()");
exit(0);
}
if(pid == 0)//子进程
{
close(pfd[1]);
err=mycpy(pfd[0],1);
if(err < 0)
{
fprintf(stderr,"%s",strerror(-err));
exit(1);
}
exit(0);
}
//父
close(pfd[0]);
fd=open(argv[1],O_RDONLY);
if(fd == -1)
{
perror("open()");
close(pfd[1]);
exit(1);
}
err2=mycpy(fd,pfd[1]);
if(err2 < 0)
{
fprintf(stderr,"%s",strerror(-err2));
exit(1);
}
close(pfd[1]);
wait(NULL);
exit(0);
}
static int mycpy(int fd1,int fd2)
{
int fd;
int cnt;
char buf[BUFSIZE];
while(1)
{
cnt=read(fd1,buf,BUFSIZE);
if(cnt == -1)
{
close(fd1);
return -errno;
}
if(cnt == 0)
{
close(fd1);
return 0;
}
write(fd2,buf,cnt);
}
}
命名管道
//进程1
llj@llj-virtual-machine:~/apueqin/few$ cd /tmp
llj@llj-virtual-machine:/tmp$ mkfifo myfifo_name
llj@llj-virtual-machine:/tmp$ date >myfifo_name
llj@llj-virtual-machine:/tmp$
//进程2
llj@llj-virtual-machine:~/apue/ipc/pipe$ cd /tmp
llj@llj-virtual-machine:/tmp$ cat myfifo_name
2021年 09月 28日 星期二 23:30:47 CST
llj@llj-virtual-machine:/tmp$
//注:两个进程要在同一路径下
//proto.h 协议
#ifndef _PROTO_H
#define _PROTO_H
#define PATHNAME "/etc/shadow"
#define PATHPID 1
#define NAMESIZE 32
struct std_st
{
char name[NAMESIZE];
int pid;
};
struct msgbuf
{
long mtype;
struct std_st stu;
};
#endif
//send.c 1号进程发送
#include
#include
#include "proto.h"
int main(int argc,char *argv[])
{
key_t key;
int msgid;
key=ftok(PATHNAME,PATHPID);
if(key == -1)
{
perror("ftok()");
exit(1);
}
msgid=msgget(key,IPC_CREAT|IPC_EXCL|0600);
if(msgid == -1)
{
if(errno == EEXIST)
{
msgid=msgget(key,0);
}
else
{
perror("msgget()");
exit(1);
}
}
struct msgbuf sndbuf;
strncpy(sndbuf.stu.name,argv[2],NAMESIZE);
sndbuf.stu.pid=atoi(argv[1]);
sndbuf.mtype=atoi(argv[3]);
msgsnd(msgid,&sndbuf,sizeof(struct std_st),0);
exit(0);
}
//recv.c 2号进程接收
#include
#include
#include
#include
#include
#include
#include "proto.h"
int main()
{
struct msgbuf rcvbuf;
//.......................................................
key_t key;
int msgid;
key=ftok(PATHNAME,PATHPID);
if(key == -1)
{
perror("ftok()");
exit(1);
}
msgid=msgget(key,IPC_CREAT|IPC_EXCL|0600);
if(msgid == -1)
{
if(errno == EEXIST)
{
msgid=msgget(key,0);
}
else
{
perror("msgget()");
exit(1);
}
}
//.......................................................建立消息队列
// struct msgbuf rcvbuf;
while(1)
{
if(msgrcv(msgid,&rcvbuf,sizeof(struct std_st),0,0) == -1)
{
perror("msgrcv()");
goto ERROR;
perror("msgrcv()");
goto ERROR;
}
fprintf(stdout,"%s",rcvbuf.stu.name);
printf("%d\n",rcvbuf.stu.pid);
}
msgctl(msgid,IPC_RMID,NULL);
exit(0);
ERROR:
msgctl(msgid,IPC_RMID,NULL);
exit(1);
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SHMSIZE 1024
int main()
{
pid_t pid;
int shmid;
char *str;
shmid=shmget(IPC_PRIVATE,SHMSIZE,IPC_CREAT|IPC_EXCL|0600);
if(shmid == -1)
{
if(errno == EEXIST)
shmid=shmget(IPC_PRIVATE,SHMSIZE,0);//创建共享内存
else
{
perror("shmget()");
shmctl(shmid,IPC_RMID,NULL);
exit(-1);
}
}
pid=fork();
if(pid == -1)
{
perror("fork()");
exit(0);
}
if(pid == 0)//send
{
str=shmat(shmid,NULL,0);//映射,NULL,由内核分配空间
memcpy(str,"good afternoon ",14);
shmdt(str);//解除映射
exit(0);
}
wait(NULL);
str=shmat(shmid,NULL,0);
puts(str);
// sleep(20);
shmdt(str);
shmctl(shmid,IPC_RMID,NULL);
exit(0);
}
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 64
static int semid;
int childJob();
int main(void)
{
pid_t pid;
int i;
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);//建立信号集,1个数组,得到信号集的id
if (-1 == semid) {
perror("semget()");
exit(1);
}
semctl(semid, 0, SETVAL, 1);//将下标为0的信号集的信号设置为一个
for (i = 0; i < 10; i++) {
pid = fork();
if (-1 == pid) {
perror("fork()");
exit(1);
}
if (pid == 0) {
childJob();
exit(0);
}
}
for (i = 0; i < 10; i++)
wait(NULL);
semctl(semid, 0, IPC_RMID, NULL);//消除信号,下标为0的
exit(0);
}
static int P()
{
struct sembuf buf;
buf.sem_num = 0;//信号集里的成员
buf.sem_op = -1;//取一个信号
buf.sem_flg = 0;//特殊要求
semop(semid, &buf, 1);
}
static int V()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;//放一个信号
buf.sem_flg = 0;
semop(semid, &buf, 1);
}
int childJob()
{
FILE *fp;
char buf[BUFSIZE] = {};
fp = fopen("./test.txt", "r+");
// 竞争
// 拿信号
P();
// io;
fgets(buf, BUFSIZE, fp);
rewind(fp);//将指针偏移量,设置在开头
// sleep(1);
fprintf(fp, "%d", atoi(buf)+1);
fclose(fp); // buf
V();
return 0;
}
//创建守护进程
static int mydaemon(void)
{
pid_t pid;
struct rlimit limit;
int fd;
umask(0);//...............................设置屏蔽字0
pid=fork();
if(pid == -1)
{
return -errno;
exit(0);
}
if( pid > 0)
exit(0);//............................fork子进程,符进程exit
setsid();//...............................建立会话
chdir("/");//.............................切换到根目录
fd=open("/dev/null",O_WRONLY);
if(fd == -1)
{
return -errno;
exit(1);
}
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);//.............................将0,1,2文件描述符重定向
getrlimit(RLIMIT_NOFILE,&limit);
for(int i=0;i
int main()
{
int err,err2;
time_t tme;
openlog("mydaemon",LOG_PID,LOG_DAEMON);//.................写日志,建立连接
err=mydaemon();//创建守护进程的接口函数
if(err < 0)
{
syslog(LOG_ERR,"mydaemon():%s",strerror(-err));//.........发送给syslog,syslog写日志
exit(1);
}
err2=runningInit();//单实例接口函数
if(err2 < 0)
{
syslog(LOG_ERR,"runningInit():%s",strerror(-err2));
exit(-1);
}
while(1)
{
system("ps aux > /text.log");
syslog(LOG_INFO,"mydaemon was sucessful");
sleep(10);
}
closelog();//...................................................断开连接
exit(0);
}
//单实例
static int runningInit(void)
{
int fd;
char buf[BUFSIZE];
fd=open(LOCKFILE,O_WRONLY|O_CREAT,0666);//打开单实例文件
if(fd == -1)
{
return -errno;
}
if(lockf(fd,F_TLOCK,0) == -1)//上
{
if(errno == EACCES ||errno == EAGAIN)
{
close(fd);
return -errno;
}
close(fd);
return -errno;
}
//第一次
ftruncate(fd,0);//.........................清空文件,截断
snprintf(buf,BUFSIZE,"%d\n",getpid());
write(fd,buf,strlen(buf)+1);//.............将pid写入单实例文件
return 0;
}
#include
#include
#include
#include
#include
#include
int main()
{
pid_t pid;
pid=fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
printf("[child] pid:%d,pgid:%d,ppid:%d,sid:%d\n",getpid(),getpgrp(),getppid(),getsid(0));
exit(0);
}
wait (NULL);
printf("[father] pid:%d,pgid:%d,ppid:%d,sid:%d\n",getpid(),getpgrp(),getppid(),getsid(0));
exit(0);
}