linux进程通信 共享内存 信号
一.共享内存
原理:A,B两个进程虽然各自内存空间不同。但是共享内存的内容同样利用映射之后再用指针挂载上去。这样可以做到A在共享内存里写数据,B马上就可以读取到。
共享内存的API
写入共享内存:
**#include <sys/shm.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include<string.h>
int main(){
key_t key;
key=ftok(".",1); //获得key值
char* addr; //指向映射共享内存的指针
int shmID;
shmID=shmget(key,sizeof(4*1024),IPC_CREAT|0666 );
addr=shmat(shmID,0,0); //两个0都指向系统默认操作
strcpy(addr,"hell world"); //往映射内存写东西
sleep(10);
shmdt(addr); //取消对共享内存的链接
shmctl(shmID,IPC_RMID,0); //卸载共享内存,0表示对卸载时候返回的参数不关心
return 0;
}**
读共享内存里的内容:
**#include <sys/shm.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include<string.h>
int main(){
key_t key;
key=ftok(".",1); //获得key值
char* addr; //指向映射共享内存的指针
int shmID;
shmID=shmget(key,sizeof(4*1024),IPC_CREAT|0666 );
addr=shmat(shmID,0,0); //两个0都指向系统默认操作
printf("%s",addr); //从映射内存读东西
shmdt(addr); //取消对共享内存的链接
shmctl(shmID,IPC_RMID,0); //卸载共享内存,0表示对卸载时候返回的参数不关心
return 0;
}**
信号
信号的名字和编号 用shell命令:kill -l 查看
例子:想要杀一个进程 如a.out 那就要调用SIGKILL 对应编号为9
首先使用 ps -aux|grep a.out 查看 进程的pid号。
kill -9 pid号 就成功给a.out进程发送了死亡信号。
信号相关的API:
signal函数
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
第一个参数:信号的编号
第二个参数 :信号的处理函数
作用:接收到对应编号的信号后,用信号处理函数做事情。
kill函数(给指定进程发送信号)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数:
pid:可能选择有以下四种
- pid大于零时,pid是信号欲送往的进程的标识。
- pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
- pid等于-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
- pid小于-1时,信号将送往以-pid为组标识的进程。
sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行。
返回值说明: 成功执行时,返回0。失败返回-1,errno被设为以下的某个值 EINVAL:指定的信号码无效(参数 sig 不合法) EPERM;权限不够无法传送信号给指定进程 ESRCH:参数 pid 所指定的进程或进程组不存在。
接收信号携带的消息
sigaction函数
https://blog.csdn.net/weibo1230123/article/details/81411827
这位老哥写的很不错。借鉴借鉴。
函数原型:
**#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);**
第二个参数:处理信号函数的指针
第三个参数:拷贝 一般用NULL
重点是第二个参数
*const struct sigaction act
这是第二个参数结构体原型
**struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};**
要收到信号带的参数,主要是第二个和第四个元素
第二个元素为处理信号函数
第四个元素要为SA_SIGINFO
处理函数原型 void (*sa_sigaction)(int, siginfo_t *, void *);
第一个参数 信号编号 第二个参数 信号所带来的信息(是一个结构体) 第三个参数处理函数内容
第二个参数有这些内容:
**siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since kernel 2.6.32) */
}**
例子:
发送带有消息的信号
sigqueue函数原型
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
主要是第三个参数:
一个联合体:
union sigval {
int sival_int;
void *sival_ptr;
};
发送信号所携带的消息,有整型,也有字符型
例子:
#include<stdio.h>
#include <signal.h>
// int sigqueue(pid_t pid, int sig, const union sigval value);
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char**argv){
int signum;
int pid;
union sigval value;
value.sival_int=100;
signum=atoi(argv[1]); // xian shu ru signum;
pid=atoi(argv[2]); // di er ge shu ru pid
sigqueue(pid,signum,value); // fa song pid signum dou wei ziji shu ru de xinhao qi zhong xinhao limian de zhi wei value ,value you tong guo union sigval value fuzhi
printf("dang qian jin chen PID=%d",getpid());
printf("fa song xin hao chengong \n\n\n\n");
return 0;
}