int signal(int sig,__sighandler_t handler); int func(int sig);
sig 指明了所要处理的信号类型,handler是SIG_IGN,SIG_DFL或者返回值为整数的函数地址。
当执行了signal函数后,进程只要接收到类型为sig 的信号,就立即执行 func()函数,不管其正在执行程序的哪一部分。当func()函数执行结束后,程序返回到进程被中断的那一点继续执行。
忽略中止信号:
#include <signal.h>
int main()
{
signal(SIGINT,SIG_IGN); /*告诉进程将 SIGINT 信号忽略*/
cout<<"start"<<endl;
sleep(3); /*在此期间,无法中止程序运行*/
cout<<"end"<<endl;
return 0;
}void fun(int sig)
{
cout<<endl;
cout<<"ctrl-c"<<endl;
}
int main()
{
signal(SIGINT,fun); /*告诉进程将 SIGINT 信号忽略*/
cout<<"start"<<endl;
sleep(3); /*中止程序运行时,调用fun函数*/
cout<<"end"<<endl;
return 0;
}输出: start ^C ctrl-c end
int kill(pid_t pid,int sig);参数 pid 指定了信号发送的对象进程。
int n=0;
void fun(int sig)
{
cout<<n++<<endl;
}
int main()
{
signal(SIGUSR1,fun);受到信号执行fun函数
pid_t pid;
pid=fork();
if(pid==0)
{
pid_t ppid=getppid();
for(int i=0;i<5;i++){kill(ppid,SIGUSR1);sleep(1);}//发送信号
}
else if(pid>0)
{
wait(NULL);
}
else
{
perror("fork Error!");
exit(1);
}
return 0;
}输出: 0 1 2 3 4
void fun(int sig)
{
cout<<"alarm 5"<<endl;
}
int main()
{
signal(SIGALRM,fun);
pid_t pid;
pid=fork();
if(pid==0)
{
pid_t ppid=getppid();
alarm(5);//设置定时器,在5秒时将发送超时信号,并终止子进程执行。
sleep(8);
}
else if(pid>0)
{
wait(NULL);
}
else
{
perror("fork Error!");
exit(1);
}
return 0;
}pause等待进程捕捉并处理信号。
void fun(int sig){}
int main()
{
signal(SIGALRM,fun);
alarm(1);
pause();//处于等待状态。
return 0;
}++++++++++++++++++管道++++++++++++++++++
实现父子进程间的通信
fd用于存放 pipe()函数新建立的管道句柄
fd[0]是从管道中读出数据的句柄
fd[1]是向管道写入数据的句柄。即fd[1]的写入由 fd[0]读出。
int main()
{
int fd[2];
char buf[100]={'\0'};
pid_t pid;
pipe(fd);//建立管道
pid=fork();//建立子进程
if(pid>0)
{
close(fd[1]);//关闭不需要的句柄
read(fd[0],buf,100);
cout<<buf<<endl;
}
else if(pid==0)
{
close(fd[0]);//关闭不需要的句柄
strcpy(buf,"hello");
write(fd[1],buf,100);
}
else {exit(1);}
return 0;
}int dup(int oldfd);
将管道句柄重定向到标准输入/输出上最小的未使用的句柄.
在使用dup函数前最好将原句柄关闭.
int main()
{
int fd[2];
char buf[100];
char tmp[100];
pid_t pid;
pipe(fd);
pid=fork();
if(pid>0)
{
close(fd[1]);
close(0);//关闭标准输入,0句柄是最小未使用句柄.
dup(fd[0]);
cin>>buf;
cout<<buf<<endl;
}
else if(pid==0)
{
close(fd[0]);
close(1);//关闭标准输出,1句柄是最小未使用句柄.
dup(fd[1]);
strcpy(tmp,"hello");
cout<<tmp<<endl;
}
else {exit(1);}
return 0;
}
dup2函数相当于
close(0);
dup(fd[0]);
这两条语句.
int main()
{
int fd[2];
char buf[100]={'\0'};
char tmp[100]={'\0'};
pid_t pid;
pipe(fd);
pid=fork();
if(pid>0)
{
close(fd[1]);
dup2(fd[0],0);
cin>>buf;//从管道读入
cout<<buf<<endl;
}
else if(pid==0)
{
close(fd[0]);
dup2(fd[1],1);
strcpy(tmp,"hello");
cout<<tmp<<endl;//读出到管道
}
else {exit(1);}
return 0;
}FILE *popen(char *command,char *type);
int pclose(FILE *stream);
popen()函数首先调用 pipe()函数建立一个管道,然后用 fork()函数建立一个子进程,运行一个 shell 环境,然后在这个 shell 环境中运行"command"参数指定的程序。数据在管道中流向由"type"参数控制。这个参数可以是"r"或者"w",分别代表读和写。
int main()
{
FILE *pipe_fp;
if((pipe_fp = popen("ps -ef","r"))== NULL)//设置一个管道读.
{
perror("popen");
exit(1);
}
char buf[100]={'\0'};
fread(buf,1,99,pipe_fp);//从管道中读.
cout<<buf<<endl;
/* 关闭管道 */
pclose(pipe_fp);
return(0);
}解决管道不能提供非父/子关系进程间通信的缺陷.
在读取数据时,若管道中没有数据,有名管道会自动阻塞直到读取到数据为止.
int mknod(char *pathname,mode_t mode,dev_t dev); pathname:要创建的文件的名称; mode:文件类型; dev:该文件对应的设备文件的设备号。只有当文件类型为 S_IFCHR 或 S_IFBLK 的时候该文件才有设备号,创建普通文件时传入0即可。
#include <sys/stat.h>
#include <unistd.h>
int main()
{
char buf[100]={'\0'};
mknod("./tmpss",S_IFIFO|0666,0);
FILE *fp=fopen("./tmpss","r");
fgets(buf,100,fp);//阻塞等待读取数据
fclose(fp);
cout<<buf<<endl;
return(0);
}管道写.int main()
{
FILE *fp = fopen("./tmpss","w")
fputs("hello",fp);
fclose(fp);
return(0);
}文件和记录锁定可分为咨询式锁定和强制锁定两种。
int lockf(int fd,int function,long size); function可以是以下取值: F_ULOCK:为一个先前锁定的区域解锁 F_LOCK:锁定一个区域,如果指定文件的对应区域已被其它进程锁定,那么 lockf 的调用进程将被阻塞直到该区域解锁。 F_TLOCK:测试并锁定一个区域,如果被测试的区域上了锁,lockf便会立即返回-1,出错返回码 errno 将为 EAGAIN. F_TEST:测试一个区域是否已经上锁。 参数 size 指明了从文件当前位置开始的一段连续锁定区域的长度,当 size 为 0 时,锁定记录将由当前位置一直扩展到文件尾。
#include <unistd.h>
int main()
{
int fd;
char buf[2]={'\0'};
if((fd=open("data",O_RDWR))<=0)
{
perror("Can't open");
exit(1);
}
if(lockf(fd,F_LOCK,0)!=-1)//阻塞直到成功加锁
{
int i=0;
while(i++<3)
{
lseek(fd,0,0);
read(fd,buf,1);
buf[0]+=1;
cout<<buf<<endl;
lseek(fd,0,0);
write(fd,buf,1);
}
ockf(fd,F_ULOCK,0);
}
close(fd);
return(0);
}连续执行两次输出start 2 3 4 start 5 6 7如果改为F_TLOCK,则只有第一个进程的输出.第二个进程没有输出.
int flock(int fd,int operation); 调用 flock 有两个参数: fd:一个已打开文件的文件描述符; operation可以是以下取值: LOCK_SH:共享锁 LOCK_EX:互斥锁 LOCK_UN:解锁 LOCK_NB:当文件已被锁定时不阻塞
#include <sys/file.h>
int main()
{
int fd;
char buf[2]={'\0'};
if((fd=open("data",O_RDWR))<=0)
{
perror("Can't open");
exit(1);
}
if(flock(fd,LOCK_EX)!=-1)//设置阻塞性互斥锁
{
int i=0;
while(i++<3)
{
lseek(fd,0,0);
read(fd,buf,1);
buf[0]+=1;
cout<<buf<<endl;
lseek(fd,0,0);
write(fd,buf,1);
}
flock(fd,F_ULOCK);
}
close(fd);
return(0);
}start 2 3 4 start 5 6 7如果是LOCK_EX | LOCK_NB,则只有第一个进程的输出.第二个进程没有输出.
key_t ftok(char *pathname,char proj);获取一个消息队列的标识符。
如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。如果两个进程没有任何关系,就用ftok()。
int msgget(key_t key,int msgflg)创建新的消息队列或获取已有的消息队列。
int msgsnd(int msqid,struct msgbuf *msgp,int msgsz,int msgflg)msqid 是消息队列对象的标识符.
int msgctl(int msgqid, int cmd, struct msqid_ds *buf)msgqid:消息队列对象的标识符。
发送消息:
#include <sys/msg.h>
struct mymsgbuf {
long msgtype;
char msgtext[100]={'\0'};
};
int main()
{
mymsgbuf buf;
buf.msgtype=1;
strcpy(buf.msgtext,"hello");
key_t key = ftok(".",'a');
int msgqueue_id = msgget(key, IPC_CREAT|IPC_EXCL|0660);
msgsnd(msgqueue_id,(mymsgbuf*)&buf,sizeof(buf.msgtext),0);
return(0);
}接受消息:struct mymsgbuf {
long msgtype;
char msgtext[100]={'\0'};
};
int main()
{
mymsgbuf buf;
key_t key = ftok(".",'a');
int msgqueue_id = msgget(key, IPC_CREAT|0660);
msgrcv(msgqueue_id,(mymsgbuf*)&buf,100,1,0);
msgctl(msgqueue_id, IPC_RMID, 0);
cout<<buf.msgtext<<endl;
return(0);
}输出:hello
struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_flg;
};
sem_num 成员为接受操作的信号量在信号量数组中的序号(数组下标)。
sem_op 成员定义了进行的操作(可以是正、负和零)。
sem_flg 是控制操作行为的标志。
如果 sem_op 是负值,就从指定的信号量中减去相应的值。
如果 sem_op 是正值,就在指定的信号量中加上相应的值。
如果 sem_op 是零,那么调用 semop()函数的进程就会被阻塞直到对应的信号量值为零。
int semget(key_t key, int nsems, int semflg);建立新的信号量对象或者获取已有对象的标识符。
IPC_EXCL:和IPC_CREAT一起使用(用”|”连接),保证所得的消息队列对象是新创建的而不是打开已有的对象。
int semop(int semid, struct sembuf *sops, unsigned nsops);改变信号量对象中各个信号量的状态。
nsops:sops数组的长度。
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
int main()
{
key_t mykey = ftok(".",'b');
sembuf sops1{0,-1,0};
sembuf sops2{0,1,0};
semun semopts;
semopts.val = 1;
int sid = semget(mykey, 1, IPC_CREAT | 0660);
semctl(sid, 0, SETVAL, semopts);
semop(sid, &sops1,1);
sleep(5);
cout<<"do something"<<endl;
semop(sid, &sops2,1);
}int main()
{
key_t mykey = ftok(".",'b');
sembuf sops1{0,-1,0};
sembuf sops2{0,1,0};
int sid = semget(mykey, 1, IPC_CREAT | 0660);
semop(sid, &sops1,1);
cout<<"another do something "<<endl;
semop(sid, &sops2,1);
semctl(sid, 0, IPC_RMID, 0);
}do something another do something
int shmget(key_t key, int size, int shmflg);创建新的或取得已有的共享内存。
int shmat(int shmid, char *shmaddr, int shmflg);将shmget()函数得到的共享内存,映射到进程自己的内存空间内。
int shmctl(int shmqid, int cmd, struct shmid_ds *buf);cmd:
int shmdt(char *shmaddr);
断开共享内存映射
一个进程发送数据
#include <sys/shm.h>
int main()
{
key_t mykey = ftok(".",'b');
int shmid = shmget(mykey, 100, IPC_CREAT|IPC_EXCL|0666);
char *segptr = (char *)shmat(shmid, 0, 0);
strcpy(segptr, "hello");
}int main()
{
key_t mykey = ftok(".",'b');
int shmid = shmget(mykey, 100, 0);
char *segptr = (char *)shmat(shmid, 0, 0);
cout<<segptr<<endl;
shmctl(shmid, IPC_RMID, 0);
}输出:hello
linux之多线程fork:进程通信,布布扣,bubuko.com
原文地址:http://blog.csdn.net/zsp_skyer/article/details/26883751