寒假学习 第16.17天 (linux 高级编程) 笔记 总结
一、进程的基本控制(进程的同步)
1.进程的常见控制函数
pause sleep/usleep
atexit on_exit
int atexit(void (*function)(void)); //注册终止函数(即main执行结束后调用的函数)
int on_exit(void (*function)(int , void *), void *arg); //跟atexit差不多,只不过函数可以带参数
#include <stdio.h> #include <unistd.h> #include <stdlib.h> void fun() { printf("over!\n"); } int main(int argc, const char *argv[]) { atexit(fun); //注册, printf("Processs!\n"); return 0; }
2.进程与文件锁(锁有共享锁跟强制锁,内核编译不同)
多进程下面文件的读写是共享的。
怎么知道一个文件正在被另外进程读写?
就是要使用文件锁。
API:
fcntl (文件锁受内核参数影响)
对文件加锁
int fcntl(int fd, int cmd, ... /* arg */ );
返回0加锁成功,-1加锁失败。
fd 加锁的文件符号
cmd 锁的操作方式 F_SETLK(如果已经加锁就异常返回) F_UNLK F_SETLCKW(已经加锁,者、则阻塞等待等到解锁)
... struct flock* 类型
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) */ ... };
例子:
setlock.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc, const char *argv[]) { int fd; struct flock lk; int r; fd=open("test.txt",O_RDWR); if(fd==-1) printf("error:%m\n"),exit(-1); lk.l_type=F_WRLCK; lk.l_whence=SEEK_SET; lk.l_start=5; lk.l_len=10; r=fcntl(fd,F_SETLK,&lk); if(r==0) printf("加锁成功!\n"); else printf("加锁失败!\n"); while(1); return 0; }
getlock.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(int argc, const char *argv[]) { int fd; struct flock lk={0}; //一定要初始化0 int r; fd=open("test.txt",O_RDWR); if(fd==-1) printf("error:%m\n"),exit(-1); r=fcntl(fd,F_GETLK,&lk); if(lk.l_type=F_WRLCK){ printf("写锁!\n"); } printf("pid:%d,start:%d, len:%d\n",r,lk.l_pid,lk.l_start,lk.l_len); return 0; }
锁也是一个进程可以共享的信息
二、信号
1.信号的作用
流程:
信号发给操作系统,操作系统查找这个信号是否注册,如果注册系统就调用函数
没有注册则采用缺省处理(一般是调用打印信号提示,并终止程序)
为了解决进程之间通信难。
作用:通知其他进程响应。(其实就是进程之间一种通信机制)
一般接受信号的进程会马上停止(软中断),并且调用信号的处理函数(默认的处理函数,或者用户的处理函数)。
例子:
2.信号的发送与安装
kill -s 信号 进程ID //向指定的进程发送信号
kill -l //可以看所有的信号 ctrl+D 就相当于发送信号2(即SIGINT)
例子:
#include <stdio.h> #include <unistd.h> #include <signal.h> void handle(int s) { printf("信息发生\n"); } int main(int argc, const char *argv[]) { signal(SIGINT,handle); //注册信号 while(1) { printf("进程在执行!\n"); sleep(1); } return 0; }当kill -s 2 pid 时(或直接ctrl+C)就会输出 “信号发送”
其中 SIGKILL与 SIGSTOP 信号是不能被处理的
int kill(pid_t pid, int sig); //发送信号
pid:如果>0 发送到指定进程
如果=0 发送信号到该进程所在进程组的所有进程
如果=-1 发送给除init (1)之外的所有进程
如果<0 发送给指定的进程组(组ID就是 它的绝对值)
例子:
#include <stdio.h> #include <unistd.h> #include <signal.h> int main(int argc, const char *argv[]) { while(1) { kill(4184,SIGINT); sleep(2); } return 0; }
3.信号的应用(实现多任务)
延时器 timeout
信号:SIGALRM
信号发送函数:unsigned int alarm(unsigned int seconds); //自向本进程发出
例子:
#include <stdio.h> #include <signal.h> void deal(int s) { printf("起床!\n"); } int main(int argc, const char *argv[]) { signal(SIGALRM,deal); alarm(5); while(1) { printf("AAAAA\n"); sleep(1); } return 0; }
定时器
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, //计时方式 ITIMER_REAL真实时间 ITIMER_VIRTUAL程序暂用cpu的时间 ITIMER_PROF 进程跟系统的混合时间
const struct itimerval *new_value, //定时器的时间参数
struct itimerval *old_value); //返回原来设置的定时器,如果NULL 者不返回。
(set interval timter)
struct itimerval {
struct timeval it_interval;// 延时时间
struct timeval it_value; //间隔时间
};
struct timeval {
time_t tv_sec; //秒
suseconds_t tv_usec; //毫秒
};
例子:
#include <stdio.h> #include <signal.h> #include <sys/time.h> void deal(int s) { printf("起床!\n"); } int main(int argc, const char *argv[]) { struct itimerval val={0}; signal(SIGALRM,deal); val.it_value.tv_sec=3; //sec跟usec都为0的表无穷时间,不会触发 val.it_interval.tv_sec=1; setitimer(ITIMER_REAL,&val,0); while(1) { printf("AAAAA\n"); sleep(1); } return 0; }3秒钟过后每隔1秒钟显示 “起床了”。