发信人: tcpip (俺的昵称改了), 信区: cnunix
标  题: 本地进程间通信第五讲:信号灯(二)
发信站: 哈工大紫丁香 (Sun Sep 26 17:10:23 1999), 转信

发信人: cpu (奔腾的心), 信区: Solaris
发信站: 华南网木棉站 (Thu Apr 15 14:38:22 1999), 转信

下面给出个用P、V操作实现进程间互斥的例子,父子进程共享一个文件来完成如下
通信:父进程从标准输入接收一行字符,写入文件,然后子进程再把内容读出来。

程序里有两个信号灯,一个是写信号灯,一个是读信号灯。写信号等的初始值为1,
表示文件的初始状态是可写的;读信号灯的初始值为0,表示文件一开始是没有内容
可读的。

程序如下:

# include <stdio.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/sem.h>
# include <signal.h>

# define  KEY_RD        (key_t)5678L
# define  KEY_WR        (key_t)6789L

int     sem_read, sem_write;
FILE    * fp;

int create_sem(key_t key)       /* create semaphore */
{
        int     semid;

        if ((semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0600)) < 0) {
                perror("semget");
                exit(-1);
        }

        return semid;
}

int my_semop(int semid, int val)        /* call by P and V functions */
{
        struct  sembuf  sbuf;
        sbuf.sem_num = 0;
        sbuf.sem_op = val;
        sbuf.sem_flg = 0;
        return (semop(semid, &sbuf, 1));
}

int P(int semid)                        /* P operation to semaphore */
{
        return (my_semop(semid, -1));
}

int V(int semid)                        /* V operation to semaphore */
{
        return (my_semop(semid, 1));
}

void sig_handler(int sig)               /* handle interrupt signal */
{
        semctl(sem_read, 0, IPC_RMID, 0);
        semctl(sem_write, 0, IPC_RMID, 0);
        fclose(fp);
        exit(0);
}

int main( )
{
        int     childpid;
        char    buf[512];

        sem_read = create_sem(KEY_RD);
        sem_write = create_sem(KEY_WR);

        signal(SIGINT, sig_handler);            /* for ctrl+c interrupt */
        signal(SIGCHLD, SIG_IGN);


        if ((fp = fopen("tmp", "w+")) == NULL) {
                perror("fopen");
                exit(-2);
        }

        V(sem_write);   /* father writable at first */

        if ((childpid = fork( )) > 0) {         /* father */
                for (;;) {
                        gets(buf);      /* get line from stdin */
                        P(sem_write);   /* waiting for file writable */
                        fseek(fp, 0, SEEK_SET);
                        fprintf(fp, "%s\n", buf);
                        fflush(fp);
                        printf("father write: %s\n", buf);
                        V(sem_read);    /* note child file readable */
                }
        } else if (childpid == 0) {             /* son */
                for (;;) {
                        P(sem_read);    /* waiting for file readable */
                        fflush(fp);
                        fseek(fp, 0, SEEK_SET);
                        fgets(buf, 512, fp);    /* read file content */
                        ftruncate(fileno(fp), 0); /* clear file content */
                        printf("son read: %s\n", buf);
                        V(sem_write);   /* note father file writable */
                }
        }
}

--

        ******************************************************

               青岛啤酒,可能是世界上最好的啤酒 。。。 。。。

        ******************************************************
※ 修改:.trueip 于 Sep 26 17:14:10 修改本文.[FROM: dns.mtlab.hit.ed]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: dns.mtlab.hit.ed]

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: trueip.bbs@melon.gzn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.441毫秒