1.内存映射
①内存映射就是把文件中的内容,复制到内存中去。
②内存映射函数:void *mmap(void *start,size_t length,int port,int flags,int fd,off_t offset)
参数说明:1.void *start : 一般该参数都为0
2.size_t length : 文件长度
3.int port :PROT_READ | PROT_WRITE 可读、可写
4. int flags:MAP|SHARED一个进程改了,其映射该文件的进程也看得见,但是没有写入文件,要写入文件需调用 msync
5.int fd:文件描述符
6.off_t offset:文件内从开始的位置
③解除映射函数:int munmap(void *start,size_t length)
④举例:
1 | #include <stdio.h> |
2 | #include <unistd.h>/*close函数*/ |
3 | #include <sys/mman.h> |
4 | #include <fcntl.h>/*open函数*/ |
5 | #define NUM (10) |
6 | typedef struct |
7 | { |
8 | int no; |
9 | char data[30]; |
10 | }RECORD; |
11 | int main() |
12 | { |
13 | RECORD *mapped; |
14 | int filde = open("records.dat", O_RDWR); |
15 | mapped = (RECORD *)mmap(0, |
16 | NUM * sizeof(RECORD), |
17 | PROT_READ | PROT_WRITE, |
18 | MAP_SHARED, |
19 | filde, |
20 | 0); |
21 | mapped[5].no = 8888; |
22 | sprintf(mapped[5].data, "Record-%d/n", mapped[5].no); |
23 | msync((void*)mapped, NUM * sizeof(RECORD), MS_ASYNC); |
24 | munmap((void*)mapped, NUM * sizeof(RECORD)); |
25 | close(filde); |
26 | return 0; |
27 | } |
2.内存共享
①创建 shmget
原型:int shmget ( key_t key, int size, int shmflg );
参数说明:
key:共享内存的键值。
size:建立共享内存的长度。
shmflg:
IPC_CREAT:如果共享内存不存在,则创建,否则打开。
IPC_EXCL:如果共享内存不存在,则建立,否则报错。
返回值:如果成功,返回共享内存段标识符。如果失败,则返回-1:
②连接 shmat
原型:void * shmat ( int shmid, char *shmaddr,int shmflg);
参数说明:
shmid:共享内存标识符;
shmaddr:进程映射地址,通常为null;
shmflg:映射地址空间访问属性,例如SHM_RDONLY;
返回值:
如果成功,则返回共享内存段连接到进程中的地址。如果失败,则返回-1:
errno = EINVAL (无效的IPC ID 值或者无效的地址)
ENOMEM (没有足够的内存)
EACCES (存取权限不够)
③解除 shmdt
调用原型:int shmdt ( char *shmaddr );
返回值:如果失败,则返回-1:errno = EINVAL (无效的连接地址)
④控制(用来删除) shmctl
函数原型:int shmctl(int shm_id, int cmd,struct shmid_ds *buf);
参数说明:
shm_id:共享内存标识符
cmd:将要采取的动作,可以取值IPC_STAT、IPC_SET、IPC_RMID,分别表示把shmid_ds结构中的数据设置为共享内存的当前关联值、按照shmid_ds设置共享内存和删除共享内存段。
buf:保存共享内存的模式状态。
⑤举例说明
1 | #include <sys/ipc.h> |
2 | #include <sys/shm.h> |
3 | #include <stdlib.h> |
4 | #include <string.h> |
5 | #include <stdio.h> |
6 | int main() |
7 | { |
8 | int pid,shmid;//后者为共享内存识别代号 |
9 | char *write_address; |
10 | char *read_address; |
11 | struct shmid_ds dsbuf; |
12 | if((shmid=shmget(IPC_PRIVATE,32,0))<0)//分配共享内存,创建 |
13 | { |
14 | printf("shmid共享内存分配出现错误。/n"); |
15 | exit(1); |
16 | } |
17 | else |
18 | printf("shmid共享内存分配成功,共享内存识别代号为:%d。/n",shmid); |
19 | if((pid=fork())<0) |
20 | { |
21 | printf("fork函数调用出现错误!/n"); |
22 | exit(2); |
23 | } |
24 | else if(pid>0)//父进程,向共享内存中写入数据 |
25 | { |
26 | printf("父进程的ID是:%d/n",getpid()); |
27 | write_address=(char *)shmat(shmid,NULL,0);//连接共享内存 |
28 | if((int)write_address==-1) |
29 | { |
30 | printf("shmat连接共享内存错误。/n"); |
31 | exit(3); |
32 | } |
33 | else |
34 | { |
35 | printf("shmat连接共享内存成功。/n"); |
36 | strcpy(write_address,"我是写入共享内存的测试数据");//将数据写入共享内存 |
37 | printf("写入共享内存的信息为“%s”。/n",write_address); |
38 | if((shmdt((void *)write_address))<0)//断开与共享内存的连接 |
39 | printf("shmdt共享内存断开错误。/n"); |
40 | else |
41 | printf("shmdt共享内存断开成功。/n"); |
42 | sleep(2); |
43 | return; |
44 | } |
45 | } |
46 | else//子进程,从共享内存中读取数据 |
47 | { |
48 | sleep(2);//等待父进程写入共享内存完毕 |
49 | printf("子进程ID是:%d/n",getpid()); |
50 | if((shmctl(shmid,IPC_STAT,&dsbuf))<0)//将shmid相关的数据结构中各个元素的当前值放入由dsbuf指向的结构中 |
51 | { |
52 | printf("shmctl获取共享内存数据结构出现错误。/n"); |
53 | exit(4); |
54 | } |
55 | else |
56 | { |
57 | printf("shmctl获取共享内存数据结构成功。/n建立这个共享内存的进程ID是:%d/n",dsbuf.shm_cpid); |
58 | printf("该共享内存的大小为:%d/n",dsbuf.shm_segsz); |
59 | if((read_address=(char *)shmat(shmid,0,0))<0)//连接共享内存 |
60 | { |
61 | printf("shmat连接共享内存出现错误。/n"); |
62 | exit(5); |
63 | } |
64 | else |
65 | { |
66 | printf("自共享内存中读取的信息为:“%s”。/n",read_address); |
67 | printf("最后一个操作该共享内存的进程ID是:%d/n",dsbuf.shm_lpid); |
68 | if((shmdt((void *)read_address))<0)//断开与共享内存的连接 |
69 | { |
70 | printf("shmdt共享内存断开错误。/n"); |
71 | exit(6); |
72 | } |
73 | else |
74 | printf("shmdt共享内存断开成功。/n"); |
75 | if(shmctl(shmid,IPC_RMID,NULL)<0)//删除共享内存及其数据结构 |
76 | { |
77 | printf("shmctl删除共享内存及其数据结构出现错误。/n"); |
78 | exit(7); |
79 | } |
80 | else |
81 | printf("shmctl删除共享内存及其数据结构成功。/n"); |
82 | exit(0); |
83 | } |
84 | } |
85 | } |
86 | } |
3.消息队列
②函数
创建
int msgget (key_t key, int flag)
—key:返回新的或已有队列的ID。
—flag:通常取值IPC_CREATE。
添加消息
int msgsnd (int msqid, struct msgbuf *msgp,size_t msgsz, int flag)
—msqid:消息队列的队列ID;
—msgp:消息内容所在的缓冲区;
—msgsz:消息的大小;
—msgflg:控制消息队列满或者到达系统上限将发生的事情,例如:设置IPC_NOWAIT则消息不发送并返回-1;清除IPC_NOWAIT则发送进程挂起直到消息队列腾出空间后返回。
接收
int msgrcv (int msqid, struct msgbuf *msgp,size_t msgsz,long msgtyp, int flag)
—msqid:消息队列的引用标识符;
—msgp:接收到的消息将要存放的缓冲区;
—msgsz:消息的大小,不包含消息类型;
—msgtyp:期望接收的消息类型,一般取值0;
—msgflg:没有相应消息可供接收时应发生的事情,例如:IPC_NOWAIT。
控制(删除)
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
③举例
1 | #include <sys/types.h> |
2 | #include <sys/ipc.h> |
3 | #include <sys/msg.h> |
4 | #include <stdio.h> |
5 | #include <string.h> |
6 | #include <stdlib.h> |
7 | int main() |
8 | { |
9 | int pid,msqid;//后者为消息队列识别代号 |
10 | struct msgbuf |
11 | { |
12 | long mtype;//消息类型 |
13 | char mtext[20];//消息内容 |
14 | }send_buf,receive_buf; |
15 | if((msqid=msgget(IPC_PRIVATE,0700))<0)//建立消息队列 |
16 | { |
17 | printf("msgget建立消息队列失败。/n"); |
18 | exit(1); |
19 | } |
20 | else |
21 | printf("msgget建立消息队列成功,该消息队列识别代号为%d。/n",msqid); |
22 | if((pid=fork())<0) |
23 | { |
24 | printf("fork()函数调用失败!/n"); |
25 | exit(2); |
26 | } |
27 | else if(pid>0)//父进程,发送消息到消息队列 |
28 | { |
29 | send_buf.mtype=1; |
30 | strcpy(send_buf.mtext,"My test information"); |
31 | printf("发送到消息队列的信息内容为:%s/n",send_buf.mtext); |
32 | if(msgsnd(msqid,&send_buf,20,IPC_NOWAIT)<0)//发送send_buf中的信息到msqid对应的消息队列 |
33 | { |
34 | printf("msgsnd消息发送失败。/n"); |
35 | exit(3); |
36 | } |
37 | else |
38 | printf("msgsnd消息发送成功。/n"); |
39 | sleep(2); |
40 | exit(0); |
41 | } |
42 | else//子进程,从消息队列中接收消息] |
43 | { |
44 | sleep(2);//等待父进程发送消息完成 |
45 | int infolen;//读到的信息数据长度 |
46 | if((infolen=msgrcv(msqid,&receive_buf,20,0,IPC_NOWAIT))<0)//自消息队列接收信息 |
47 | { |
48 | printf("msgrcv读取信息错误。/n"); |
49 | exit(4); |
50 | } |
51 | else |
52 | printf("msgrcv读取信息成功。/n"); |
53 | printf("自消息队列读取到的内容为%s,共读取%d个字节。/n",receive_buf.mtext,infolen); |
54 | if((msgctl(msqid,IPC_RMID,NULL))<0)//删除msqid对应的消息队列 |
55 | { |
56 | printf("msgctl函数调用出现错误。/n"); |
57 | exit(5); |
58 | } |
59 | else |
60 | { |
61 | printf("识别代号为%d的消息队列已经被成功删除。/n",msqid); |
62 | exit(0); |
63 | } |
64 | } |
65 | } |
4.信号量
①semget
功能:创建一个新信号量或取得一个已有信号量的标志符
函数原型:int semget(key_t key,int nsems,int semflg);
“key” 参数
—预定义常数IPC_PRIVATE
—约定的关键字
—ftok函数
“semflg” 参数
—设置访问权限(低9位)
—IPC_CREAT, IPC_EXCL 按位或
“nsems”
—指定需要的信号量数目,几乎总是取值为1。
例:sem_id = semget((key_t)1234, 1,0666 | IPC_CREAT);
②semop
功能:改变信号量的值
函数原型为:int semop(int semid,struct sembuf *sops,size_t nsops);
“sops” 参数
struct sembuf
{
unsigned short sem_num; /* 信号量编号*/
short sem_op;
/* 信号量操作*/
short sem_flg;
/* 操作标志*/
}
nsops参数
结构数组的元素个数
sem_flg:
sem_flg用于对操作进行适当的控制,主要有2个控制标志。
IPC_NOWAIT:当指定的操作不能完成时,进程不等待立即返回,返回值为-1,errno置为EAGAIN。
SEM_UNDO(建议):进程退出时,执行信号量解除(undo)操作。
P():
int semaphore_p(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_p failed/n");
return(0);
}
return(1);
}
V():
static int semaphore_v(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed/n");
return(0);
}
return(1);
}
③semctl
功能:控制,删除
函数原型:int semctl(int semid,int semnum,int cmd,union semun arg);
参数说明:
int semid:信号标识符
int semnum:设置为0
int cmd:信号集操作
union semun
{
int val;
/*用于SETVAL命令,指明要设置的值*/
struct semid_ds *buf;
/*用于IPC_STAT/IPC_SET命令,用来存放信号量集合数据结构*/
unsigned short *array;
/*用于GETALL/SETALL命令,用来存放所获得的或是要设置信号量集合中所有信号量的值*/
} arg;
“cmd”parameter:
IPC_RMID:删除信号量集合
SETVAL:设置信号量集合中由semnum指定的单个信号量的值(设为arg.val)
④set
1 | int set_semvalue(void) |
2 | { |
3 | union semun sem_union; |
4 | sem_union.val = 1; |
5 | if (semctl(sem_id, 0, SETVAL, sem_union) == -1) |
6 | return(0); |
7 | return(1); |
8 | } |
⑤del
1 | void del_semvalue(void) |
2 | { |
3 | union semun sem_union; |
4 | if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) |
5 | fprintf(stderr, "Failed to delete semaphore/n"); |
6 | } |