您的位置:首页 > 运维架构 > Linux

c++ 学习笔记(高级linux编程) day6

2014-08-19 18:30 471 查看
linux高级编程day06 笔记

问题解答:

1.exit(状态码)返回状态码有什么意义?

返回值被系统得到.系统根据状态码进行日志记录.

返回值被调用者得到:system/wait.程序会根据返回状态码进行对应处理。

exit(状态码)=main函数中的return 状态码;

2.状态码的第二个字节才是exit()的返回值或者return值。

一.进程的基本控制

1.进程的常见控制函数

1.1.为什么需要控制进程?

1.2.pause/sleep/usleep

1.3.atexit on_exit

#include <stdio.h>

#include <stdlib.h>

void fun()

{

printf("over\n");

}

main()

{

atexit(fun); //注册终止函数(即main执行结束后调用的函数)

printf("Process!\n");

}

2.进程与文件锁

在多进程下文件读写是共享的

问题:

怎么知道一个文件正在被另外进程读写?

解决方案:

文件锁。(建议锁)

API:

fcntl(文件锁受内核参数影响)

编程技巧:

对文件加锁

判定一个文件是否存在锁

函数说明:

int fcntl(

int fd,//被加锁的文件描述符号

int cmd,//锁的操作方式:F_SETLK(已经加锁,异常返回)F_UNLK F_SETLKW(已经加锁,则阻塞等待)

struct flock *lk);//锁的描述

返回值:

0:加锁成功

-1:加锁失败

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

main()

{

int fd;

struct flock lk;

int r;

//打开一个文件

fd=open("a.txt",O_RDWR);

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;

//加锁

r=fcntl(fd,F_SETLK,&lk);

if(r==0) printf("加锁成功!\n");

else printf("加锁失败!\n");

while(1);

}

案例:

写两个程序:

A:加锁

B:获取锁的信息

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

main()

{

int fd;

struct flock lk;

int r;

//打开一个文件

fd=open("a.txt",O_RDWR);

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=3;

//加锁

r=fcntl(fd,F_SETLK,&lk);

if(r==0) printf("加锁成功!\n");

else printf("加锁失败!\n");

while(1);

}

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

main()

{

int fd;

struct flock lk={0};

int r;

fd=open("a.txt",O_RDWR);

if(fd==-1) printf("::%m\n"),exit(-1);

r=fcntl(fd,F_GETLK,&lk);

if(r==0)

printf("得到锁成功!\n");

if(lk.l_type==F_WRLCK)

{

printf("写锁!\n");

}

printf("start:%d,len:%d\n",lk.l_start,lk.l_len);

printf("PID:%d\n",lk.l_pid);

}

锁也是一个进程可以共享的信息。

二.信号

1.信号的作用

背景:

进程之间通信比较麻烦。

但进程之间有必须通信,比如父子进程之间。

作用:

通知其他进程响应。进程之间通信机制.

信号:

接受信号的进程马上停止.调用信号处理函数.

信号处理函数:

默认处理函数.

打印信号信息,退出进程.

用户处理函数.

中断:

软中断.

案例:

1.进程之中,默认信号处理

2.进程之中,用户信号处理

#include <unistd.h>

#include <stdio.h>

#include <signal.h>

void handle(int s)

{

printf("我是信号发生!\n");

}

main()

{

//signal(SIGWINCH,handle);

signal(35,handle);

while(1)

{

//printf("进程在执行:%d!\n",getpid());

//sleep(1);

}

}

3.中断

kill -s 信号 进程ID

kill -信号 进程ID

信号:数字1-31 34-64

宏SIGINT=2

ctrl+d 发送信号2 SIGINT

kill -l察看所有信号

信号SIGKILL SIGSTOP不能被处理.

案例:

发送信号

int kill(pid_t pid,int s)

进程ID:

>0:发送信号到指定进程

=0:发送信号到该进程所在进程组的所有进程

-1:发送给所有进程,除init外

<0:发送给指定的进程组(组ID=绝对值)

#include <stdio.h>

#include <signal.h>

main()

{

int i;

//while(1)

for(i=0;i<5;i++)

{

kill(4601,35);

}

}

2.信号发送与安装

signal

kill

3.信号的应用

3.1.延时器timeout

SIGALRM

信号发出函数:alarm

3.2.定时器

int setitimer(int which,//计时方式

//ITIMER_REAL / ITIMER_VIRTUAL /ITIMER_PROF

const struct itimerval *val,//定时器的时间参数

struct itimer *oldval);//返回原来设置的定时器

//如果=NULL,则不返回

struct itimerval

{

struct timeval it_interval;//间隔时间

struct timeval it_value;//延时时间

}

struct timeval

{

long tv_sec;

long tv_usec;

}

#include <stdio.h>

#include <signal.h>

#include <sys/time.h>

void deal(int s)

{

printf("起床!\n");

}

main()

{

struct itimerval v={0};

signal(SIGALRM,deal);

//v.it_value.tv_sec=3; //程序启动3秒后触发,可以不设定tv_usec

v.it_value.tv_sec=0;

v.it_value.tv_usec=1; //让程序一启动就触发。不能设为0

v.it_interval.tv_sec=1; //间隔1秒

//alarm(5);

setitimer(ITIMER_REAL,&v,0);

while(1)

{

//.....

}

}

信号应用:

系统与应用程序之间

应用于应用程序之间

父子进程之间

案例1:

使用定时器信号,实现多任务.

实现:

实现7位随机数

使用中断实现时间的显示

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <math.h>

#include <curses.h>

WINDOW *w;

int num;

int isstop=0;

void handle(int s)

{

if(s==SIGUSR1)

{

if(isstop==1)

isstop=0;

else

isstop=1;

}

}

main()

{

initscr();

curs_set(0);//隐藏光标

noecho();//禁止输入回显

//keypad(stdscr,TRUE);

//keypad(w,TRUE);

//创建子窗体

w=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);

box(w,0,0);//给子窗体加边框

refresh();

wrefresh(w);

if(fork())

{

//显示7位数的随机数

signal(SIGUSR1,handle);

while(1){

if(isstop==1)

{

pause();//pause会被信号中断停止 ***

}

num=rand()%10000000;//产生7位随机数

mvwprintw(w,1,2,"%07d",num);//显示随机数

refresh();//刷新屏幕。

wrefresh(w);

usleep(10000);//暂停10毫秒

}

}

else

{

//处理按键

while(1)

{

getch();

//if(ch==KEY_ENTER)

{

kill(getppid(),SIGUSR1);

}

}

}

endwin();

}

案例2:

实现父子进程之间通信

控制进程.

sleep与pause函数被信号影响后,sleep不再继续sleep.

pause不再pause.

练习:

1.在curses显示7位随机数

其他信号函数

raise

4.信号的可靠与不可靠以及信号的含义

信号有丢失.(信号压缩)

由于历史的缘故:信号有压缩的需求.

可靠信号(实时信号)与不可靠信号(非实时信号).

早期信号 1-31 31个信号, 不可靠(与系统有关).

后期信号34-64 31个信号,可靠信号(用户信号)

5.信号的操作

信号导致的问题

1.信号屏蔽

int sigprocmask(int how,//操作方式

SIG_BLOCK

SIG_UNBLOCK

SIG_SETMASK

const sigset_t *sigs,//操作的信号集合

sigset_t *oldsigs);//返回原来操作的信号集合

1.声明信号集合

sigset_t sigs;

2.加入屏蔽信号

一组信号集合维护函数:

2.1. 清空集合sigemptyset

2.2. 添加信号到集合sigaddset

2.3. 从集合删除信号sigdelset

2.4. 添加所有信号到集合sigfillset

2.5. 判定信号是否在集合sigismember

3.屏蔽信号

4.接触屏蔽

2.信号屏蔽的切换

int sigsuspend(sigset_t *sigs);

屏蔽新的信号,原来的信号失效.

sigsuspend是阻塞函数.对参数信号屏蔽.

对参数没有指定的信号不屏蔽,但当没有屏蔽信号处理函数调用完毕

sigsuspend返回条件:

1.信号发生,并且信号是非屏蔽信号

2.信号必须要处理,而且处理函数返回后,sigsuspend才返回.

sigsuspend设置新的屏蔽信号,保存旧的屏蔽信号

而且当sigsuspend返回的时候,恢复旧的屏蔽信号.

#include <stdio.h>

#include <signal.h>

void h(int s)

{

printf("非屏蔽信号发生!\n");

}

main()

{

sigset_t sigs;

signal(SIGWINCH,h);

sigemptyset(&sigs);

sigaddset(&sigs,2);

printf("屏蔽开始!\n");

sigsuspend(&sigs);

printf("屏蔽结束!\n");

}

3.查询被屏蔽的信号

int sigpending(sigset_t *sets);

#include <stdio.h>

#include <signal.h>

void h(int s)

{

printf("抽空处理int信号\n");

}

main()

{

int sum=0;

int i;

//1.

signal(SIGINT,h);

sigset_t sigs,sigp,sigq;

//2.

sigemptyset(&sigs);

sigemptyset(&sigp);

sigemptyset(&sigq);

sigaddset(&sigs,SIGINT);

//3.

sigprocmask(SIG_BLOCK,&sigs,0);

for(i=1;i<=10;i++)

{

sum+=i;

sigpending(&sigp);

if(sigismember(&sigp,SIGINT))

{

printf("SIGINT在排队!\n");

sigsuspend(&sigq);

//使原来屏蔽信号无效,开放原来信号

//使新的信号屏蔽,

//当某个信号处理函数处理完毕

//sigsuspend恢复原来屏蔽信号,返回

}

sleep(1);

}

printf("sum=%d\n",sum);

sigprocmask(SIG_UNBLOCK,&sigs,0);

printf("Over!\n");

}

回顾:

1.进程控制sleep pause

2.理解信号的中断流程

3.发射信号(Shell/code),处理信号

4.alarm与setitimer

5.信号应用:实现简单多任务与进程之间通信

6.使用信号+sleep/pause控制进程

7.信号的屏蔽

8.了解sigpending与 sigsuspend的使用.

作业:

1.写一个程序,创建两个子进程,分别计算1-5000与5001-1000素数,

通过信号让,父进程专门完成数据保存.

2.完成课堂上的作业:

显示7位随机数,同时使用定时器信号显示时间

在使用键盘控制7位随机数的停止与继续显示.

(建议美化)

3.完成如下作业:

在屏幕水平同时显示移动两个字符.

思考:

信号处理函数调用过程中,是否被其他信号影响.

明天:

1.信号与进程间数据传递

sigqueue=kill与sigaction=signal

2.IPC:

基于文件

无序文件:映射

有序文件:管道文件:有名/匿名

socket文件

基于内存

无序内存

内存共享

有序内存

共享队列
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: