共享内存通信:允许两个不相干的进程访问同一个逻辑内存,让连个正在运行的进程传输数据的有效方式。
原理:进程有特定的的进程控制块和地址空间和与空间对应的页表,页表将虚拟地址和物理地址进行映射,通过内存管理MMU管理,不同的虚拟地址通过页表映射至物理空间的同一地址。
函数ipcs
相关头文件<sys/ipc.h> <sys/shm.h>
查看共享存储段:ipcs -m
删除共享存储段:ipcrm -m [shmid]
shmget()创建共享内存:int shmget(key_t key(标识系统的唯一IPC资源),size_t size(共享内存大小),int shmflg(设置访问权限比如0641)|IPC_CREAT);创建情况下还须追加IPC_CREAT
成功返回一个共享标识符
失败返回-1
shmat()挂件共享内存
void *shmat(int shmid(共享内存段标识符),const void *shmaddr(NULL,则存储段连接到由内核选择的第一个地址上),int shmflg(设定权限));
成功返回指针/虚拟地址 失败返回-1
shmctl()销毁共享内容
int shmctl(int shmid(共享存储段标识符),int cmd(指定的执行操作,IPC_RMID),struct shmid_ds *buf(NULL));
例程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define SHMKEY 75 //定义键值,也可通过ftok进行生成
int shmid, i;
int *addr=NULL;
void client(void)
{
int i;
shmid = shmget(SHMKEY, 1024, 0777);//获得已有的共享内存段
if(shmid==-1)
{
printf("client()... shmget() fail!\n");
exit(1);
}
printf("client() shmid=%d\n",shmid);
addr = (int *)shmat(shmid, NULL, 0);//挂接共享内存
for(i=9;i>=0;i--)
{
while(-1 != *addr) ;//addr的内容是-1,就跳出循环
printf("(client) server save *addr=%d\n",*addr);
*addr= i;
printf("(client) sent *addr=%d\n",i);
}
exit(0);
}
void server(void)
{
//shmget()创建共享内存段
//参1:SHMKEY=75
//参2:1024字节
//参3:授予权限|IPC_CREAT
shmid = shmget(SHMKEY, 1024, 0777 | IPC_CREAT);
if(shmid==-1)
{
printf("servre()...shmget() fail!\n");
exit(1);
}
printf("server() shmid=%d\n",shmid);
//addr: 前面定义的是 int *addr
//shmat()挂载共享内存段
//参1:shmid,共享内存段标识符
//参2:NULL 采用系统默认
//参3: 控制读写权限,0:可以读写,SHM_RDONLY:只读
addr = (int *)shmat(shmid, NULL, 0);
do
{
*addr= -1;
while (*addr== -1) ;//addr里面的内容==-1,则死循环此句
printf("(server) received addr的内容=%d\n",*addr);
} while (*addr);//*addr不等于0,继续循环
shmctl(shmid, IPC_RMID, 0);
exit(0);
}
int main()
{
while (-1 == (i = fork())) ;//直到创建新进程成功,才会下一步
if(!i)//i==0时,条件成立,进入子1进程
{
server();//server()功能由子1进程完成
}
system("ipcs -m");//同时父进程:调用ipcs命令查看IPC
while (-1 == (i= fork())) ;
if(!i)
{
client();//client()功能由子2进程完成
}
wait(NULL);//等子进程结束
wait(NULL);//等子进程结束
system("ipcs -m");
return 0;
}
进程组和会话
进程组:一个或多个进程的集合,通常与一组作业相关联,可以接受来自同一终端的信号
getpgrp:获取进程组id,即领头进程id
相关头文件<unistd>
pid_t getpgrp(void); 返回调用进程组ID
printf("%d\n",getgpid);打印进程组id
创建会话
调用进程不能是进程组组长,该进程变成新绘画首进程
该进程成为一个新进程组的组长进程
新会话丢弃原有的控制终端(转入后台)
调用进程为组长进程则出错
getsid函数 pid_t getsid(pid_t pid)
成功返回进程会话ID,失败返回-1
setsid函数 pid_t setsid(void)
setsid函数的进程,是新的组长和会长
setsid后pgid和sid都被改变
守护进程:一类在后台运行,执行特定的工作。在系统启动时启动,运行至系统关闭。必要时启动,完成后自动关闭
不受任何终端控制
创建
创建子进程,父进程退出
父进程必须终止,之前孤儿进程变成主要进程
在子进程中创建新会话:setsid()使子进程独立出来,脱离控制
改变当前目录chdir(绝对路径):防止占用可卸载的文件系统,也可以换成其他路径
重设文件权限掩码umask(文件访问权限掩码比如00(可读可写)2(写)2)
关闭文件描述符close(文件描述符)
将标准输入标准输出标准错误全部重定向至/dev/null
fd=open("/dev/null",O_RDWR);fd指向0
while(1)模拟守护进程业务逻辑要求