|
所用到的相关函数:
通过读写者问题(不考虑优先级)来测试共享内存和信号量的配合应用。这里的读写者问题要求一个进程读共享内存时,其他进程不能写内存:当一个进程写共享内存时,其他进程不能读内存。
程序里首先定义了一个包含公用函数的头文件 sharemem.h 。
sharemem.h 代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#define SHM_SIZE 1024
/*semun 联合体最少要包含下面定义的3个元素*/
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
/*创建信号量函数*/
int createsem (const char *pathname, int proj_id, int members, int init_val)
{
key_t msgkey;
int index, sid;
union semun semopts;
/*创建key*/
if ((msgkey = ftok (pathname, proj_id)) == -1) {
perror ("ftok error!\n");
return (-1);
}
/*利用创建的key产生信号集标识符*/
if ((sid = semget (msgkey, members, IPC_CREAT | 0666)) == -1) {
perror ("semget call failed. \n");
return (-1);
}
/*初始化*/
semopts.val = init_val;
for (index = 0; index < members; index++) {
semctl (sid, index, SETVAL, semopts);
}
return (sid);
}
/*打开信号量*/
int opensem (const char *pathname, int proj_id)
{
key_t msgkey;
int sid;
if ((msgkey = ftok (pathname, proj_id)) == -1) {
perror ("ftok error!\n");
return (-1);
}
if ((sid = semget (msgkey, 0, IPC_CREAT | 0666)) == -1) {
perror ("semget call failed. \n");
return (-1);
}
return (sid);
}
/*P操作*/
int sem_p (int semid, int index)
{
struct sembuf buf = {0, -1, IPC_NOWAIT};
if (index < 0) {
perror ("index of array cannot equals a minus value!");
return (-1);
}
buf.sem_num = index;
if (semop (semid, &buf, 1) == -1) {
perror ("a wrong operation to semaphore occurred!");
return (-1);
}
return (0);
}
/*V操作*/
int sem_v (int semid, int index)
{
struct sembuf buf = {0, 1, IPC_NOWAIT};
if (index < 0) {
perror ("index of array cannot equals a minus value!");
return (-1);
}
buf.sem_num = index;
if (semop (semid, &buf, 1) == -1) {
perror ("a wrong operation to semaphore occurred!");
return (-1);
}
return 0;
}
/*删除信号集*/
int sem_delete (int semid)
{
return (semctl (semid, 0, IPC_RMID));
}
/*等待信号为1*/
int wait_sem (int semid, int index)
{
int second = 0;
while (semctl (semid, index, GETVAL, 0) == 0) {
sleep (1);
printf ("Can not enter the shared memory for %ds\n", second);
second += 1;
}
printf ("Can Enter The Shared Memory!\n");
return (1);
}
/*创建内存函数*/
int createshm (char *pathname, int proj_id, size_t size)
{
key_t shmkey;
int sid;
if ((shmkey = ftok (pathname, proj_id)) == -1) {
perror ("ftok error!\n");
return (-1);
}
if ((sid = shmget (shmkey, size, IPC_CREAT | 0666)) == -1) {
perror ("shmget call failed. \n");
return (-1);
}
return (sid);
}
写者代码:
#include "sharemem.h"
int main()
{
int semid, shmid;
int len;
char *shmaddr;
char write_str [SHM_SIZE];
/*创建共享内存*/
if ((shmid = createshm (".", 'm', SHM_SIZE)) == -1) {
exit (1);
}
/*附加共享内存到进程空间*/
if ((shmaddr = shmat (shmid, (char *)0, 0)) == (char *)-1) {
perror ("attach shared memory error!\n");
exit (1);
}
/*创建信号量集,这里信号量集中只有一个信号量(一般情况下也只需要一个)*/
if ((semid = createsem (".", 's', 1, 1)) == -1) {
exit (1);
}
while (1) {
wait_sem (semid, 0); /*等待信号量释放已进入共享内存区*/
sem_p (semid, 0); /*P操作*/
printf ("write: ");
fgets (write_str, 1024, stdin);
len = strlen (write_str) - 1;
write_str [len] = '\0';
strcpy (shmaddr, write_str); /*标准输入内容复制到共享内存区*/
sleep (10); /*测试信号量锁定:使reader处于阻塞状态*/
sem_v (semid, 0); /*V操作,释放信号量*/
sleep (10); /*等待 reader 进行读操作*/
}
}
读者代码:
#include "sharemem.h"
int main ()
{
int semid, shmid;
char *shmaddr;
/*得到由写者创建共享内存区的标识符*/
if ((shmid = createshm (".", 'm', SHM_SIZE)) == -1) {
exit (1);
}
/*attach 共享内存区到自己的进程空间*/
if ((shmaddr = shmat (shmid, (char *)0, 0)) == (char *)-1) {
perror ("attach shared memory error!\n");
exit (1);
}
/*得到信号量集标识符*/
if ((semid = opensem (".", 's')) == -1) {
exit (1);
}
while (1) {
printf ("reader: \n");
wait_sem (semid, 0); /*等待信号值1*/
sem_p (semid, 0); /*P操作*/
printf ("%s\n", shmaddr);
sleep (10); /*使 writer 处于阻塞状态*/
sem_v (semid, 0); /*V操作*/
sleep (10); /*等待 write 进行写操作*/
}
} 测试运行,先运行写者的程序:beyes@linux-beyes:~/C/share_memory> ./writer.exe
Can Enter The Shared Memory!
write: 上面,写者程序已经进入到内存共享区,然后利用信号量将共享区锁定,不允许别的进程进入并等待用户从输入内容以送到共享内存区中。
假如没有读者程序的读取而只是在写者程序里输入内容,那么在等待 20s 后,写者程序重新进入内存共享区:beyes@linux-beyes:~/C/share_memory> ./writer.exe
Can Enter The Shared Memory!
write: hello reader!
Can Enter The Shared Memory!
write:
运行读者程序,这时如果写者程序没有在共享内存区中输入内容,那么读者会一直被阻塞,因为写者程序没有释放信号量:beyes@linux-beyes:~/C/share_memory> ./reader.exe
reader:
Can not enter the shared memory for 0s
Can not enter the shared memory for 1s
Can not enter the shared memory for 2s
Can not enter the shared memory for 3s
Can not enter the shared memory for 4s
Can not enter the shared memory for 5s
... ...
现在在写者程序一侧输入内容(同时读者程序已经对读取不到共享内存区数据计时已达10秒):
经过 10s 后,写者程序释放了信号量,读者程序已经可以进入到共享内存区并读取到内容:... ...
Can not enter the shared memory for 11s
Can not enter the shared memory for 12s
Can not enter the shared memory for 13s
Can not enter the shared memory for 14s
Can not enter the shared memory for 15s
Can not enter the shared memory for 16s
Can not enter the shared memory for 17s
Can not enter the shared memory for 18s
Can not enter the shared memory for 19s
Can not enter the shared memory for 20s
Can not enter the shared memory for 21s
Can Enter The Shared Memory!
hello reader! |
|