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

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

2014-08-19 18:33 537 查看
linux高级编程day07 笔记

回顾:

1.信号的作用

2.理解信号:

软中断

可靠与不可靠信号kill -l

3.信号发送与注册kill/raise alarm setitimer signal

4.信号的屏蔽sigprocmask sigemptyset sigfillset ...

5.信号屏蔽的切换

sigpending

sigsuspend

=pause+

指定屏蔽信号

pause与sigsuspend都回被信号中断.

中断的是pause与sigsuspen,不是进程中其他代码

sigsuspend放在sigprocmask环境中思考:

5.1.sigsuspend是否影响sigprocmask屏蔽的信号呢?

影响.使原来的屏蔽信号全部失效.

当sigsuspend返回,恢复原来的屏蔽信号.

5.2.sigsuspend什么时候使用?

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <unistd.h>

void handle(int s)

{

printf("信号干扰!\n");

}

main()

{

int sum=0;

int i;

sigset_t sigs,sigt;

sigemptyset(&sigs);

sigemptyset(&sigt);

sigaddset(&sigs,SIGINT);

//sigfillset(&sigs);

signal(SIGINT,handle);

sigprocmask(SIG_BLOCK,&sigs,0);

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

{

sum+=i;

sleep(5);//模拟业务处理时间比较长

sigsuspend(&sigt);

sleep(5);

}

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

sigprocmask(SIG_UNBLOCK,&sigs,0);

printf("over!\n");

}

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <unistd.h>

void handle(int s)

{

printf("外部用户中断处理...!\n");

sleep(3);

printf("外部用户中断处理完毕!\n");

}

main()

{

int sum=0;

int i;

sigset_t sigs,sigt,sigu;

sigemptyset(&sigs);

sigemptyset(&sigt);

sigemptyset(&sigu);

sigaddset(&sigs,SIGINT);

//sigfillset(&sigs);

signal(SIGINT,handle);

sigprocmask(SIG_BLOCK,&sigs,0);

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

{

printf("正在拷贝电影<%d>!\n",i);

sleep(5);//模拟业务处理时间比较长

printf("正在拷贝电影<%d>完毕!\n",i);

sigpending(&sigu);

if(sigismember(&sigu,SIGINT))

{

sigsuspend(&sigt);

}

}

printf("所有电影拷贝完毕\n",sum);

sigprocmask(SIG_UNBLOCK,&sigs,0);

printf("over!\n");

}

一.最新版本的信号发送与处理

sigqueue/sigaction

1.思考:信号中断函数调用中是否被其他信号中断.

信号函数调用中只屏蔽本身信号,不屏蔽其他信号.

2.怎么保证函数调用中屏蔽指定的信号呢?

sigaction可以指定处理函数调用的屏蔽信号

sigaction在处理信号的时候,接受数据.

sigqueue发送信号的时候,可以发送数据.

sigaction/sigqueue是signal/kill的增强版本

#include <stdio.h>

#include <signal.h>

#include <unistd.h>

main()

{

union sigval val;

val.sival_int=8888;

sigqueue(3972,SIGUSR1,val);

}

3.函数说明

使用sigaction/sigqueue有两个理由.

3.1.稳定

3.2.增强功能

int sigaction(

int sig,//被处理信号

const struct sigaction*action,//处理函数及其参数

struct sigaction*oldact//返回原来的处理函数结构体

)

返回:

0:成功

-1:失败

struct sigaction

{

void (*sa_handle)(int);

void (*sa_sigaction)(int,siginfo_t*,void*);

sigset_t *mask;//屏蔽信号

int flags;//SA_SIGINFO

void**//保留成员.

}

#include <stdio.h>

#include <signal.h>

#include <unistd.h>

/*

void handle(int s)

{

printf("OOOK!\n");

sleep(5);

printf("K000!\n");

}*/

void handle(int s,siginfo_t* info,void *d)

{

printf("OOOK:%d\n",info->si_int);

sleep(5);

printf("K000!\n");

}

main()

{

struct sigaction act={0};

//act.sa_handler=handle;

act.sa_sigaction=handle;

sigemptyset(&act.sa_mask);

sigaddset(&act.sa_mask,SIGINT);

act.sa_flags=SA_SIGINFO;

sigaction(SIGUSR1,&act,0);

while(1);

}

案例:

1.使用sigaction处理信号,使用kill发送信号

2.使用sigaction处理信号,使用sigqueue发送信号

3.发送信号的同时处理数据

二.IPC

1.基于文件

1.1.无序文件

1.1.有序文件

1.1.1.管道

1.1.1.1.有名

1.1.1.2.匿名

1.1.2.socket

2.基于内存

2.1.无序内存

2.1.1.匿名内存

2.1.2.共享内存

2.2.有序内存

2.2.1.共享队列

3.同步:基于内存IPC应用(共享内存数组)

信号量/信号灯

三.基于普通文件的IPC

IPC的技术提出的应用背景.

进程之间需要同步处理:

同步需要通信.

普通文件就是最基本的通信手段.

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

main()

{

int *p;

int fd;

int i;

fd=open("tmp",O_RDWR|O_CREAT,0666);

ftruncate(fd,4);

p=mmap(0,4,PROT_READ|PROT_WRITE,

MAP_SHARED,fd,0);

i=0;

while(1)

{

sleep(1);

*p=i;

i++;

}

close(fd);

}

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

main()

{

int *p;

int fd;

fd=open("tmp",O_RDWR);

p=mmap(0,4,PROT_READ|PROT_WRITE,

MAP_SHARED,fd,0);

while(1)

{

sleep(1);

printf("%d\n",*p);

}

close(fd);

}

普通文件IPC技术的问题:

一个进程改变文件,另外一个进程无法感知.

解决方案:

一个特殊的文件:管道文件

四.管道文件

1.创建管道mkfifo

2.体会管道文件特点

案例:

fifoA fifoB

建立管道

打开管道 打开管道

写数据 读数据

关闭管道 关闭管道

删除管道

建立管道文件:

使用linux的指令mkfifo

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/stat.h>

#include <signal.h>

#include <stdlib.h>

int fd;

int i;

void end(int s)

{

//关闭管道

close(fd);

//删除管道

unlink("my.pipe");

exit(-1);

}

main()

{

signal(SIGINT,end);

//建立管道

mkfifo("my.pipe",0666);

//打开管道

fd=open("my.pipe",O_RDWR);

//shutdown(fd,SHUT_RD);

i=0;

while(1)

{

//每隔1秒写数据

sleep(1);

write(fd,&i,4);

i++;

}

}

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/stat.h>

#include <signal.h>

#include <stdlib.h>

int fd;

void end(int s)

{

//关闭管道

close(fd);

exit(-1);

}

main()

{

int i;

//打开管道

signal(SIGINT,end);

fd=open("my.pipe",O_RDWR);

//shutdown(fd,SHUT_WR);

while(1)

{

read(fd,&i,4);

printf("%d\n",i);

}

}

总结:

1.read没有数据read阻塞,而且read后数据是被删除

2.数据有序

3.打开的描述符号可以读写(two-way双工)

4.管道文件关闭后,数据不持久.

5.管道的数据存储在内核缓冲中.

五.匿名管道

发现有名的管道的名字仅仅是内核识别是否返回同一个fd的标示.

所以当管道名失去表示作用的时候,实际可以不要名字.

在父子进程之间:打开文件描述后创建进程.

父子进程都有描述符号. 管道文件没有价值.

所以在父子进程中引入一个没有名字的管道:匿名管道.

结论:

匿名管道只能使用在父子进程.

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

main()

{

int fd[2];

pipe(fd);

if(fork())

{//parent

close(fd[0]);//只负责写

while(1)

{

write(fd[1],"Hello",5);

sleep(1);

}

}

else

{//child

char buf[20];

int r;

close(fd[1]);//只负责读

while(1)

{

r=read(fd[0],buf,20);

buf[r]=0;

printf("::%s\n",buf);

}

}

}

1.创建匿名管道

2.使用匿名管道

案例:

匿名管道的创建

体会匿名管道的特点

int pipe(int fd[2]);//创建管道.打开管道.拷贝管道.关闭读写

fd[0]:只读(不能写)

fd[1]:只写(不能读)

注意:数据无边界.

综合:

建立两个子进程:

一个负责计算1-5000的素数

另外一个负责计算5001-10000

父进程负责存储

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>

#include <signal.h>

#include <stdlib.h>

#include <string.h>

#include <sched.h>

int idx=0;

int fddata;

void handle(int s)

{

int status;

if(s==SIGCHLD)

{

wait(&status);

idx++;

if(idx==2)

{

close(fddata);

printf("任务完成\n");

exit(-1);

}

}

}

int isprimer(int ta)

{

int i=2;

for(;i<ta;i++)

{

if(ta%i==0)

{

return 0;

}

}

return 1;

}

main()

{

int a,b;

int id=1;

int fd[2];

signal(SIGCHLD,handle);

pipe(fd);

while(1)

{

if(id==1){

a=2;b=50000;

}

if(id==2){

a=50001;b=100000;

}

if(fork()){

id++;

if(id>2){

break;

}

continue;

}

else{

//子进程

int i;

close(fd[0]);

for(i=a;i<=b;i++)

{

if(isprimer(i))

{

write(fd[1],&i,sizeof(int));

}

sched_yield();

}

printf("%d任务完成!\n",getpid());

exit(0);

}

}

int re;

char buf[20];

//打开文件,准备存储

close(fd[1]);

fddata=open("result.txt",

O_RDWR|O_CREAT,0666);

while(1)

{

read(fd[0],&re,sizeof(int));

sprintf(buf,"%d\n",re);

write(fddata,buf,strlen(buf));

sched_yield();

}

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