linux高階程式設計day07 筆記 (轉)
阿新 • • 發佈:2018-12-27
回顧:
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.思考:訊號中斷函式呼叫中是否被其他訊號中斷.
訊號函式呼叫中只遮蔽本身訊號,不遮蔽其他訊號.(signal)
因為遮蔽本身,所以這過程中的訊號打來依然會排隊。(不可靠會壓縮)
2.怎麼保證函式呼叫中遮蔽指定的訊號呢?
sigaction可以指定處理函式呼叫的遮蔽訊號,所以signal是用sigaction來實現遮蔽本身訊號的。(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);
}
#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();
}
}
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);
//
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
{
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.思考:訊號中斷函式呼叫中是否被其他訊號中斷.
訊號函式呼叫中只遮蔽本身訊號,不遮蔽其他訊號.(signal)
因為遮蔽本身,所以這過程中的訊號打來依然會排隊。(不可靠會壓縮)
2.怎麼保證函式呼叫中遮蔽指定的訊號呢?
sigaction可以指定處理函式呼叫的遮蔽訊號,所以signal是用sigaction來實現遮蔽本身訊號的。(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();
}
}