Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

LINUX编程学习笔记(十五) 进程控制 文件锁 信号处理与屏蔽

$
0
0

一 进程的基本控制

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_PRO 
const 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);


#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())
	}
	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");
		}
	}
}


3查询被屏蔽的信号

sigpending函数返回在送往进程的时候被阻塞挂起的信号集合。
这个信号集合通过参数set返回
 int sigpending(sigset_t *set);

#include <stdio.h>
#include <signal.h>
int main()
{
	sigset_t sigs,sigp; 
	sigemptyset(&sigs);
	sigemptyset(&sigp);
	sigaddset(&sigs,SIGINT);
	sigprocmask(SIG_BLOCK,&sigs,0);
	int sum=0;
	int i;
	for(i=1;i<=10;i++)
	{
		sum+=i;
		sleep(1);
		sigpending(&sigp); //查询正在排队中的信号
		if(sigismember(&sigp,SIGINT))
		{
			printf("SIGINT正在排队\n");
		}
	}
	printf("sum=%d\n",sum);
	sigprocmask(SIG_UNBLOCK,&sigs,0);
	printf("over!\n");
}


按下ctrl+c 后 之后每次循环中都会打印SIGINT正在排队

作者:a8887396 发表于2013-6-21 10:56:48 原文链接
阅读:22 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>