LINUX编程学习笔记(十五) 进程控制 文件锁 信号处理与屏蔽
来源:互联网 发布:数控机床编程入门基础 编辑:程序博客网 时间:2024/06/05 01:19
原地址:http://blog.csdn.net/a8887396/article/details/9143347
一 进程的基本控制
1 进程的常见控制函数
1.1 为什么需要控制进程?
1.2 休眠 pause/sleep/usleep
1.3 on_exit atexit
int atexit(void (*function)(void));int on_exit(void (*function)(int , void *), void *arg);
注册一个函数,在调用exit或者main函数return前调用。
atexit的函数较简单,无参数
on_exit的函数函数中int是exit或者rerurn的返回值(1字节的 不需要宏解析),void*是后面的arg
可以注册多次,但只调用一次。
多进程中子进程会复制该注册,但只要运行一次其他的都被取消。
- #include <stdio.h>
- #include <stdlib.h>
- void func()
- {
- printf("before over\n");
- }
- int main()
- {
- printf("Process\n");
- atexit(func);
- return 0;
- }
- #include <stdio.h>
- #include <stdlib.h>
- void func(int statue,void *args)
- {
- printf("before over\n");
- printf("statue = %d\n",statue);
- printf("args = %s\n",(char *)args);
- }
- int main()
- {
- printf("Process\n");
- char *str = "hello";
- on_exit(func,(void *)str);
- return 99;
- }
zhao@ubuntu:~/unix/6$ ./a.out
Process
before over
statue = 99
args = hello
2 进程与文件锁
在多进程下文件读写是共享的问题:怎么知道一个文件正在被另外进程读写?
解决方案: 文件锁(默认是建议锁 强制锁需重编译内核)
API:
fcntl (文件锁受内核参数影响)
编程技巧:
对文件加锁
判定一个文件是否存在锁
函数说明:
int fcntl(
int fd, //被加锁的文件描述符
int cmd, //锁的操作方式: F_SETLK (若已加锁,异常返回) F_SETLKW(若已加锁则等待) F_UNLK(解锁)
struct flock *fk //锁的描述
);
struct flock {
...
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(F_GETLK only) */
...
};
加锁
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <stdio.h>
- int main()
- {
- int fd;
- struct flock lk={0};
- //打开一个文件
- fd = open("test",O_RDWR|O_CREAT,0666);
- if(fd == -1)
- {
- printf("::%m\n"),exit(-1);
- }
- //描述锁
- lk.l_type = F_WRLCK;
- lk.l_whence=SEEK_SET;
- lk.l_start=5;
- lk.l_len=10;
- //加锁
- int r = fcntl(fd,F_SETLK,&lk);
- if(r == 0) printf("加锁成功\n");
- else
- {
- printf("加锁失败\n");
- }
- while(1);//程序结束自动解锁
- }
注意这里只是对5 到 10加了锁 当加锁区域不一样时 还可以成功加上另外的锁
如果区域重叠 就会导致加锁失败
读锁
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- int main()
- {
- int fd;
- struct flock lk={0}; //要是不初始化 就不能成功得到锁
- fd = open("test",O_RDWR);
- if(fd <0)
- {
- printf("::%m\n"),exit(-1);
- }
- int r = fcntl(fd,F_GETLK,&lk); //F_GETLK
- if(r == 0)
- {
- printf("得到锁成功\n");
- }
- else
- {
- printf("得到锁失败\n");
- }
- if(lk.l_type == F_WRLCK)
- {
- printf("写锁\n");
- }
- printf("start:%d,len %d\n",lk.l_start,lk.l_len);
- }
解锁
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <stdio.h>
- int main()
- {
- int fd;
- struct flock lk={0};
- //打开一个文件
- fd = open("test",O_RDWR|O_CREAT,0666);
- if(fd == -1)
- {
- printf("::%m\n"),exit(-1);
- }
- //描述锁
- lk.l_type = F_WRLCK;
- lk.l_whence=SEEK_SET;
- lk.l_start=20;
- lk.l_len=10;
- //加锁
- int r = fcntl(fd,F_SETLK,&lk);
- if(r == 0) printf("加锁成功\n");
- else
- {
- printf("加锁失败\n");
- }
- sleep(3);
- /* 。。。对文件进行操作。。。*/
- lk.l_type = F_UNLCK;
- r = fcntl(fd,F_SETLK,&lk);
- if(r == 0) printf("解锁成功\n");
- else
- {
- printf("解锁失败\n");
- }
- }
注意 这些都只是建议锁,即使你读取到有锁,或者加锁失败,你都还可以对文件进行操作
二 信号
1 信号的作用
通知其他进程相应。进程间的一种通信机制。接收信号的进程会马上停止,执行信号处理函数。(软中断)
1.1进程之中,默认的信号处理
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- int main()
- {
- while(1)
- {
- printf("进程在执行\n");
- sleep(1);
- }
- }
怎么发信号: kill -s 信号 进程id
kill -s 1 7038 //向进程7038中 发送信号1
kill -s SIGUP 7038 //使用信号的宏
kill -l 查看所有信号
进程在执行
进程在执行
进程在执行
进程在执行
进程在执行
挂起
ctrl+c 相当与发送信号2 SIGINT 中断信号
1.2进程之中,用户的信号处理
一个进程只能绑定一个函数一个函数可以绑定在多个进程上
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- void handle(int s)
- {
- printf("我是信号%d\n",s);
- sleep(2);
- }//函数返回后 主进程才继续
- int main()
- {
- signal(SIGINT,handle); //注册信号处理函数
- while(1)
- {
- printf("进程在执行\n");
- sleep(1);
- }
- }
进程在执行
^C我是信号2
进程在执行
^C我是信号2
进程在执行
^C我是信号2
进程在执行
进程在执行
进程在执行
发现ctrl+c 发送的是信号2
发现关不掉 kill -s 9
注意:信号SIGKILL SIGSTOP 不能被处理
2 信号的发送与安装、
int kill(pid_t pid, int sig);//向进程pid发送sig信号进程ID:
>0 发送信号到指定进程
=0 发送信号到该进程所在进程组的所有进程
-1 发送所有进程 不包含init
<-1 发送给指定的进程组 (组ID=绝对值)
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- int main()
- {
- while(1)
- {
- kill(7323,SIGINT);
- sleep(5);
- }
- }
3 信号的应用
3.1 延时器
SIGALRM信号发出函数 alarm
3.2 定时器
int setitimer(int which, //计时方式 ITIMER_REAL ITMER_VIRTUAL ITIMER_PROconst struct itimerval *val, // 定时器的时间参数
struct itimer *oldval); // 返回原来设置的定时器
ITIMER_REAL: 以系统真实的时间来计算,它送出SIGALRM信号。(常用)
ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
struct itimerval {
struct timeval it_interval; /* next value */ 间隔时间
struct timeval it_value; /* current value */ 延时时间
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
oldval 可以设置为null 不接收
- #include <signal.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/time.h>
- void deal(int s)
- {
- printf("起床!\n");
- }
- int main()
- {
- signal(SIGALRM,deal);
- struct itimerval v={0}; //创立一个结构体 结构体又有两个结构体
- v.it_interval.tv_sec = 3;
- v.it_interval.tv_usec = 1;
- v.it_value.tv_sec =5;
- v.it_value.tv_usec = 0;
- //5秒后 每隔3秒1微秒 发出SIGALRM信号
- setitimer(ITIMER_REAL,&v,NULL);
- while(1)
- {
- }
- }
4 信号的可靠与不可靠以及信号的含义
信号有丢失(信号压缩)由于历史的缘故:信号有压缩的需求
可靠信号(实时信号)与不可靠信号(非实时信号)
早期信号 1-31 31个信号都是不可靠(与系统有关,系统会产生)。
最早31个中留了SIGUSR1 SIGUSR2给用户使用
后期信号 34-64 31个信号 ,可靠信号(用户信号)
跟系统打交道,使用早期信号
处理用户产生的信号,使用可靠信号
5 信号的操作
1 信号屏蔽
int sigprocmask(int how, //操作方式:SIG_BLOCK屏蔽 SIG_UNBLOCK解除屏蔽 SIG_SETMASK修改屏蔽const sigset_t *set,// 操作的信号集合
sigset_t *oldset); // 返回原来的被屏蔽的集合
编程步骤
1 声明信号集合
sigset_t sigs;
2 加入屏蔽信号
信号结合屏蔽函数
清空集合 sigemptyset
添加信号到集合 sigaddset
从集合删除信号 sigdelset
将所有信号加进去 sigfillset
判断信号是否在集合中 sigismember
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
查询正在排队的信号(已收到 但被sigprocmask屏蔽的信号)
int sigpending(sigset_t *set);
sigpending() returns the set of signals that are pending for delivery
to the calling thread (i.e., the signals which have been raised while
blocked). The mask of pending signals is returned in set.
- #include <stdio.h>
- #include <signal.h>
- int main()
- {
- sigset_t sigs; //屏蔽集合
- sigset_t sig;
- sigemptyset(&sigs);//清空集合
- sigemptyset(&sig);//清空集合
- sigaddset(&sigs,SIGINT);//
- sigprocmask(SIG_BLOCK,&sigs,0); //开始屏蔽
- int sum=0;
- int i;
- for(i=1;i<=10;i++)
- {
- sum+=i;
- sleep(1);
- sigpending(&sig);//查询正在排队(被屏蔽)的信号
- if(sigismember(&sig,SIGINT)){ printf("SIGINT正在排队!\n");}
- }
- printf("sum=%d\n",sum);
- sigprocmask(SIG_UNBLOCK,&sigs,0); //解除屏蔽
- printf("over!\n");
- }
2 信号屏蔽的切换
sigsuspend 信号屏蔽切换int sigsuspend(const sigset_t *mask);
sigsuspend 暂时取代目前的屏蔽信号,然后挂起进程,直到一个信号,调用一个信号处理程序或终止该进程。
1如果该信号终止该过程sigsuspend不会返回。
2 如果信号被捕获,处理完信号处理函数首,sigsuspend()会返回,且恢复以前的屏蔽信号。
SIGKILL或SIGSTOP无法屏蔽
这个函数的主要作用是将中断限制在一定的范围内。比如signal产生的中断可能发生在任何地方
- #include <stdio.h>
- #include <signal.h>
- void handle(int s)
- {
- printf("SIGINT处理中\n");
- }
- int main()
- {
- signal(SIGINT,handle);
- sigset_t sigp,sigq,sigs;
- sigemptyset(&sigp);
- sigemptyset(&sigq);
- sigemptyset(&sigs);
- sigaddset(&sigp,SIGINT);
- sigprocmask(SIG_BLOCK,&sigp,0);
- printf("屏蔽SIGINT开始\n");
- int i = 0,sum=0;
- for(;i<10;i++)
- {
- sum += i;
- sleep(1);
- sigpending(&sigq);//得到排队中的信号
- if(sigismember(&sigq,SIGINT))
- {
- printf("SIGINT正在排队\n");
- sigsuspend(&sigs);//只能在这里产生SIGINT的中断
- printf("SIGINT处理结束\n");
- }
- }
- }
0 0
- LINUX编程学习笔记(十五) 进程控制 文件锁 信号处理与屏蔽
- Linux高级编程 第六章 进程控制 信号 定时器 信号操作 信号屏蔽
- UNIX环境编程学习笔记(24)——信号处理进阶学习之信号集和进程信号屏蔽字
- 嵌入式Linux进程与信号(学习笔记)
- 《unix/linux编程实践教程》学习笔记:第六章 终端控制与信号
- 十五、Linux系统编程-信号(二)信号分类、可靠信号与不可靠信号、信号发送 pause
- linux进程中的信号屏蔽
- linux信号处理--通过发送信号控制进程
- Linux程序设计学习笔记----异步信号与线程属性控制
- Linux C语言程序设计(十五)——进程、线程与信号
- APUE学习笔记——信号、信号集和进程信号屏蔽字
- linux 进程学习笔记-进程信号sigal
- Linux信号产生与处理机制学习笔记(一)
- Linux信号产生与处理机制学习笔记(二)
- Linux网络编程--信号阻塞与屏蔽(block,unblock)
- linux学习 进程控制编程
- LInux进程控制与编程
- LInux进程控制与编程
- APP在2014年的发展趋势会发生什么变化
- File GeoDatabase API简介
- 计算机网络之数据链路层
- 深入浅出话VC++(1)——Windows程序内部运行机制
- 列出数据库中子表上没有对应索引的外键
- LINUX编程学习笔记(十五) 进程控制 文件锁 信号处理与屏蔽
- 单反基础知识
- jQuery - AJAX get() 和 post() 方法(二十六)
- linux中fork()函数详解
- sift算法的主要步骤
- open-drain, push-pull,MOSFET, MOS管,三极管等基础知识
- 如果当初学编程时能有人给我这些忠告该多好
- 关于垃圾回收CollectGarbage()的使用
- 一个经典的文件拷贝程序