PHP进程通信-共享内存的使用

1.共享内存的介绍

共享内存是最高效的IPC机制,它不涉及进程之间的任何数据传输。每个进程都可以访问一块共享的区域进行读写操作。Linux的共享API,定义在sys/shm.h头文件里,共享内存的操作分为3个步骤:

1.创建或获取共享内存

2.将共享内存与进程地址关联

3. 使用完之后,与进程分离 。

Linux平台,可以通过 ipcs -m 查看共享内存的使用情况

2.PHP中使用共享内存的条件

php中支持两种共享内存的操作,分别为Shared MemorySemaphore,前者在编译的时候加上  –enable-shmop 参数,后者支持共享内存、信号量、消息队列等编译参数分别为 –enable-sysvsem–enable-sysvshm–enable-sysvmsg 。这几种共享内存的方式都是基于System V系统的。

3.使用Shared Memory的演示

<?php

$shm_key = ftok(__FILE__, 's');

$memory_size = 10;

$max_num = 10;

$shm_id = shmop_open($shm_key, 'c', 0644, $memory_size);

$child = [];

$pid = pcntl_fork();

if ($pid == -1) {
    exit;
} else if ($pid) {
    $child[] = $pid;
} else {
    $res = shmop_read($shm_id, 0, $memory_size);
    $i = 0;
    if (empty(trim($res))) {
        while($i < $max_num+1) {
            shmop_write($shm_id, $i++ , 0);
            printf('Pid:%d 写入数据:%d'.PHP_EOL, posix_getpid(), $i);
            sleep(1);
        }
    }
    exit;
}

while( ($val = (int)trim(shmop_read($shm_id, 0, $memory_size))) < $max_num) {
    printf('Pid:%d 读取数据:%d'.PHP_EOL, posix_getpid(), $val);
    sleep(1);
}


while(count($child) > 0) {
    foreach($child as $k => $pid) {
        $res = pcntl_waitpid($pid, $status, WNOHANG);
        if ($res == -1 || $res > 0) {
            unset($child[$k]);
        }
    }
}

shmop_delete($shm_id);

shmop_close($shm_id);


4.多进程并发操作共享内存的使用

<?php

const KEY = 1; // int

$memory_size = 100; //byte

$shm_id = ftok(__FILE__, 's');

$memory = shm_attach($shm_id, $memory_size, 0666);

if (!$memory) return ;

$sem_id = ftok(__FILE__, 'c');

$signal = sem_get($shm_id);

$child = [];

$max = 1000;

for($i = 0; $i < 3; $i++) {
    $pid = pcntl_fork();

    if ($pid == -1) {
        exit;
    } else if ($pid) {
        $child[] = $pid;
    } else {
        while (true) {
            sem_acquire($signal);

            if (shm_has_var($memory, KEY)) {
                $val = shm_get_var($memory, KEY);
                if ($val < $max) {
                    printf('Pid:%d 读取数据:%d' . PHP_EOL, posix_getpid(), $val);

                    shm_put_var($memory, KEY, ++$val);

                } else {
                    sem_release($signal);
                    break;
                }
            } else {
                shm_put_var($memory, KEY,0);

                printf('Pid:%d 第一次写入数据:%d' . PHP_EOL, posix_getpid(), 0);
            }
            sem_release($signal);
        }
        exit;
    }
}



while (count($child) > 0) {
    foreach ($child as $k => $pid) {
        $res = pcntl_waitpid($pid, $status, WNOHANG);

        if ($res == -1 || $res > 0) {
            unset($child[$k]);
        }
    }
}

shm_remove($memory);

sem_remove($signal);
通过信号量,并发操作共享内存

5.对于信号量的补充

信号量(Semaphore)的概念是Dijkstra在1965年提出的,它解决了多进程并发操作共享资源而产生竞态条件的问题。其主要思路就是产生一块由信号量维护的临界区 (类似加锁的概念) ,在临界区内的操作是独占的。

假设有信号量SV,则对它的P(消耗资源)、V(释放资源)操作如下

P操作:如果SV>0,则SV-1, 如果SV==0, 则阻塞进程。

V操作:如果其他进程因为等待SV而处于阻塞状态,则唤醒。如果没有,则SV+1

如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。

发表评论

电子邮件地址不会被公开。 必填项已用*标注