曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 7936|回复: 0
打印 上一主题 下一主题

共享内存与信号量应用实例1(读写者问题)

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-9-6 10:46:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
所用到的相关函数
通过读写者问题(不考虑优先级)来测试共享内存和信号量的配合应用。这里的读写者问题要求一个进程读共享内存时,其他进程不能写内存:当一个进程写共享内存时,其他进程不能读内存。

程序里首先定义了一个包含公用函数的头文件 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秒):
write: hello reader!

经过 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!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 20:16 , Processed in 0.083765 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表