寒假学习 第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秒钟显示 “起床了”。