共享内存通过信号量控制读写
来源:互联网 发布:c语言cos函数源代码 编辑:程序博客网 时间:2024/05/16 07:38
信号量函数定义如下:
#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);
int semget(key_t key, int num_sems, int sem_flags);
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
事实上,为了获得我们特定操作所需要的#define定义,我们需要在包含sys/sem.h文件之前通常需要包含sys/types.h与sys/ipc.h文件。而在某些情况下,这并不是必须的。
因为我们会依次了解每一个函数,记住,这些函数的设计是用于操作信号量值数组的,从而会使用其操作向比单个信号量所需要的操作更为复杂。
注意,key的作用类似于一个文件名,因为他表示程序也许会使用或是合作所用的资源。相类似的,由semget所返回的并且为其他的共享内存函数所用的标识符与由fopen函数所返回 的FILE*十分相似,因为他被进程用来访问共享文件。而且与文件类似,不同的进程会有不同的信号量标识符,尽管他们指向相同的信号量。key与标识符的用法对于在这里所讨论的所有IPC程序都是通用的,尽管每一个程序会使用独立的key与标识符。
semget
semget函数创建一个新的信号量或是获得一个已存在的信号量键值。
int semget(key_t key, int num_sems, int sem_flags);
第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为不同的程序通过提供一个key来间接访问的,对于每一个信号量系统生成一个信号量标识符。信号量键值只可以由semget获得,所有其他的信号量函数所用的信号量标识符都是由semget所返回的。
还有一个特殊的信号量key值,IPC_PRIVATE(通常为0),其作用是创建一个只有创建进程可以访问的信号量。这通常并没有有用的目的,而幸运的是,因为在某些Linux系统上,手册页将IPC_PRIVATE并没有阻止其他的进程访问信号量作为一个bug列出。
num_sems参数是所需要的信号量数目。这个值通常总是1。
sem_flags参数是一个标记集合,与open函数的标记十分类似。低九位是信号的权限,其作用与文件权限类似。另外,这些标记可以与IPC_CREAT进行或操作来创建新的信号量。设置IPC_CREAT标记并且指定一个已经存在的信号量键值并不是一个错误。如果不需要,IPC_CREAT标记只是被简单的忽略。我们可以使用IPC_CREAT与IPC_EXCL的组合来保证我们可以获得一个新的,唯一的信号量。如果这个信号量已经存在,则会返回一个错误。
如果成功,semget函数会返回一个正数;这是用于其他信号量函数的标识符。如果失败,则会返回-1。
semop
函数semop用来改变信号量的值:
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。
最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量,如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清理我们的信号量。
semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息。
semctl
semctl函数允许信号量信息的直接控制:
int semctl(int sem_id, int sem_num, int command, ...);
第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是unionsemun,根据X/OPEN规范,这个参数至少包括下列参数:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}
许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。
有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。
这两个通常的command值为:
SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
IPC_RMID:当信号量不再需要时用于删除一个信号量标识。
semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。
#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);
int semget(key_t key, int num_sems, int sem_flags);
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
事实上,为了获得我们特定操作所需要的#define定义,我们需要在包含sys/sem.h文件之前通常需要包含sys/types.h与sys/ipc.h文件。而在某些情况下,这并不是必须的。
因为我们会依次了解每一个函数,记住,这些函数的设计是用于操作信号量值数组的,从而会使用其操作向比单个信号量所需要的操作更为复杂。
注意,key的作用类似于一个文件名,因为他表示程序也许会使用或是合作所用的资源。相类似的,由semget所返回的并且为其他的共享内存函数所用的标识符与由fopen函数所返回 的FILE*十分相似,因为他被进程用来访问共享文件。而且与文件类似,不同的进程会有不同的信号量标识符,尽管他们指向相同的信号量。key与标识符的用法对于在这里所讨论的所有IPC程序都是通用的,尽管每一个程序会使用独立的key与标识符。
semget
semget函数创建一个新的信号量或是获得一个已存在的信号量键值。
int semget(key_t key, int num_sems, int sem_flags);
第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为不同的程序通过提供一个key来间接访问的,对于每一个信号量系统生成一个信号量标识符。信号量键值只可以由semget获得,所有其他的信号量函数所用的信号量标识符都是由semget所返回的。
还有一个特殊的信号量key值,IPC_PRIVATE(通常为0),其作用是创建一个只有创建进程可以访问的信号量。这通常并没有有用的目的,而幸运的是,因为在某些Linux系统上,手册页将IPC_PRIVATE并没有阻止其他的进程访问信号量作为一个bug列出。
num_sems参数是所需要的信号量数目。这个值通常总是1。
sem_flags参数是一个标记集合,与open函数的标记十分类似。低九位是信号的权限,其作用与文件权限类似。另外,这些标记可以与IPC_CREAT进行或操作来创建新的信号量。设置IPC_CREAT标记并且指定一个已经存在的信号量键值并不是一个错误。如果不需要,IPC_CREAT标记只是被简单的忽略。我们可以使用IPC_CREAT与IPC_EXCL的组合来保证我们可以获得一个新的,唯一的信号量。如果这个信号量已经存在,则会返回一个错误。
如果成功,semget函数会返回一个正数;这是用于其他信号量函数的标识符。如果失败,则会返回-1。
semop
函数semop用来改变信号量的值:
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
}
第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。
最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量,如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清理我们的信号量。
semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息。
semctl
semctl函数允许信号量信息的直接控制:
int semctl(int sem_id, int sem_num, int command, ...);
第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是unionsemun,根据X/OPEN规范,这个参数至少包括下列参数:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}
许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。
有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。
这两个通常的command值为:
SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
IPC_RMID:当信号量不再需要时用于删除一个信号量标识。
semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。
信号量与共享内存的共同使用例子:
write 端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <errno.h> #include "sem.h" typedef struct { char buf[1024]; }memory; int main(int argc, const char *argv[]) { key_t key; memory *p = NULL; int shmid; int create_flag = 0; int sem_id; if ((key = ftok(".", 'a')) < 0) { perror("failed to get key"); exit(-1); } if ((sem_id = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL)) < 0) { if (errno == EEXIST) { if ((sem_id = semget(key, 1, 0666)) < 0) { perror("failed to semget"); exit(-1); } } } init_sem(sem_id, 0); if ((shmid = shmget(key, sizeof(memory), 0666 | IPC_CREAT | IPC_EXCL)) < 0) { if (errno == EEXIST) { if ((shmid = shmget(key, sizeof(memory), 0666)) < 0) { perror("failed to shmget memory"); exit(-1); } } else { perror("failed to shmget"); exit(-1); } } else create_flag = 1; if ((p = shmat(shmid, NULL, 0)) == (void *)(-1)) { perror("failed to shmat memory"); exit(-1); } while(1) { printf(">"); fgets(p->buf, sizeof(p->buf), stdin); p->buf[strlen(p->buf) - 1] = 0; sem_v(sem_id); if (strncmp(p->buf, "quit", 4) == 0) break; } if (create_flag == 1) { if (shmdt(p) < 0) { perror("failed to shmdt memory"); exit(-1); } if (shmctl(shmid, IPC_RMID, NULL) == -1) { perror("failed to delete share memory"); exit(-1); } delete_sem(sem_id); } return 0; } (2)read.c(读端)[cpp] view plaincopyprint? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <errno.h> #include "sem.h" typedef struct { char buf[1024]; }memory; int main(int argc, const char *argv[]) { key_t key; int shmid; memory *p = NULL; int create_flag = 0; int sem_id; if ((key = ftok(".", 'a')) < 0) { perror("failed to get key"); exit(-1); } if ((sem_id = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL)) < 0) { if (errno == EEXIST) { if ((sem_id = semget(key, 1, 0666)) < 0) { perror("failed to semget"); exit(-1); } } } init_sem(sem_id, 0); if ((shmid = shmget(key, sizeof(memory), 0666 | IPC_CREAT | IPC_EXCL)) < 0) { if (errno == EEXIST) { if ((shmid = shmget(key, sizeof(memory), 0666)) < 0) { perror("failed to create share memory"); exit(-1); } } else { perror("failed to shmget"); exit(-1); } } else create_flag = 1; if ((p = shmat(shmid, NULL, 0)) == (void *)(-1)) { perror("failed to shmat"); exit(-1); } while(1) { sem_p(sem_id); if (strncmp(p->buf, "quit", 4) == 0) break; printf("recv: %s\n", p->buf); } if (create_flag == 1) { if (shmdt(p) < 0) { perror("failed to shmdt"); exit(-1); } if (shmctl(shmid, IPC_RMID, NULL) == -1) { perror("failed to delete share memory"); exit(-1); } delete_sem(sem_id); } return 0; }程序实现: 创建一个写端和一个读端,写端写入数据后读端才开始读,读端读完数据后,写端才可以开始写,这样的同步采用信号机制实现,并且写端与读端打开顺序不同也能实现功能;
- 共享内存通过信号量控制读写
- 进程间通信:用信号量实现对共享内存读写顺序的控制
- 进程间通信:用信号量实现对共享内存读写顺序的控制
- 共享内存及信号量控制实例
- posix信号量对system V共享内存的同步控制
- 通过共享内存和信号量实现进程间的通信
- 共享内存+信号量 实例
- 利用信号量共享内存
- 信号量,共享内存
- 共享内存和信号量
- 共享内存+信号量 实例
- 信号量和共享内存
- 信号量 与共享内存
- php 信号量(共享内存)
- 共享内存,信号量
- linux操作系统编程——共享内存读写(采用信号量进行同步互斥)
- 信号量 消息队列 共享内存
- IPC参数(共享内存/信号量)
- 2009 Q.E.D
- 2010 回归线
- A*寻径算法新手入门
- RegexOptions.Compiled真的是性能杀手么?
- 回头再说:jQuery跨域原理
- 共享内存通过信号量控制读写
- 回头再说:Uploadify跨域上传原理
- .Net 4 StringBuilder新增Clear方法及其实现
- .Net 4.0 延迟初始化:Lazy<T>
- 2010再见,你好2011
- 我在豆瓣4年
- [Erlang 0001] 我们为什么选择Erlang
- [Erlang 0002] Erlang IDE
- [Erlang 0003] 编译Erlang程序