zoukankan      html  css  js  c++  java
  • 作为phper既然了解共享内存函数shmop的使用方法,那么就必须要了解一下信号量是什么,以及信号量使用的代码案例

    在单独的一个PHP进程中读写、创建、删除共享内存方面上你应该没有问题了。但是实际运行中不可能只是一个PHP进程在运行中。如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题--著名的并行和互斥问题。比如说有2个进程同时需要对同一段内存进行读写。当两个进程同时执行写入操作时,你将得到一个错误的数据,因为该段内存将之可能是最后执行的进程的内容,甚至是由2个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。为了解决这个问题,我们必须引入互斥机制。互斥机制在很多操作系统的教材上都有专门讲述,这里不多重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另外一种进程间(IPC)的方式,它同其他IPC机构(管道、FIFO、消息队列)不同。

    说到信号量可能大家都很陌生,作为php肯定知道mysql、redis中的锁,当然还有php文件锁。说白了就是锁,用来解决进程(线程同步的问题),访问前获取锁(获取不到则等待),访问后释放锁。

    信号量的作用就是,考虑是否有多个进程同时写入数据到共享内存的情况,是否需要避免冲突。

    举一个生活中的例子:以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。

    记得给环境开启两个扩展【enable-shmop --enable-sysvsem】

    因为php默认不支持这些函数,所以需要重编译php。如要使用:
    System V信号量,编译时加上 –enable-sysvsem
    System V共享内存,编译时加上 –enable-sysvshm
    System V消息队列,编译时加上 –enable-sysvmsg
    Shared Memory,编译时加上 –enable-shmop

     

    信号量系列函数

    <?php
    //1、创建信号量唯一标识符
    $key = 0x4337b101;
    //2、创建信号量资源ID
    $sem_resouce_id = sem_get($key);
    //3、接受信号量
    sem_acqure($sem_resource_id);
    //4、释放信号量
    sem_release($sem_resource_id);
    //5、销毁信号量
    sem_remove($sem_resource_id);

     简单小案例

    <?php
    
    $key = 0x4337b101; 
    $sem_id = sem_get($key);
    //请求信号控制权
    if (sem_acquire($sem_id)) {
        $shm_id = shmop_open($key, 'c', 0644, 1024);
        //读取并写入数据
           $count = (int) shmop_read($shm_id, 0, 8) + 1;
        shmop_write($shm_id, str_pad($count, 8, '0', STR_PAD_LEFT), 0);
        // echo shmop_read($shm_id, 0, 8);
        //关闭内存块
        shmop_close($shm_id);
        //释放信号
        sem_release($sem_id);
    }

    如果出现报错:Warning: sem_release(): SysV semaphore 140680297324568 (key 0x4337b101) is not currently acquired in /usr/local/nginx/html/index.php on line 38

    那是因为没有获得锁~

    在Linux下命令观察,查看系统共享内存,信号量,队列

    # ipcs

    # ipcs -s  //单独查看信号量的话,使用ipcs -s命令

    稍微复杂的案例

    <?php
    //创建共享内存区域
    $shm_key = ftok(__FILE__, 'a');
    $shm_id = shm_attach($shm_key, 1024, 0755);
     
    //var_dump($shm_id);die(); resource(4) of type (sysvshm)
    const SHARE_KEY = 1;
    $child_list = [];
     
    //加入信号量
    $sem_id = ftok(__FILE__, 'b');
    $signal = sem_get($sem_id);
     
    //$signal resource(5) of type (sysvsem)
     
     
    for ($i = 0; $i < 3; $i++) {
      $pid = pcntl_fork();
      if ($pid == -1) {
        exit("Fork fail!".PHP_EOL);
      } elseif ($pid == 0) {
        //获取信号量
        sem_acquire($signal);
        if (shm_has_var($shm_id,SHARE_KEY)) {
          $count = shm_get_var($shm_id, SHARE_KEY);
          $count++;
          //模拟业务处理
          $sec = rand(1, 3);
          sleep($sec);
          shm_put_var($shm_id, SHARE_KEY, $count);
        } else {
          $count = 0;
          $sec = rand(1, 3);
          sleep($sec);
          shm_put_var($shm_id, SHARE_KEY, $count);
        }
     
        echo "child process: ".getmypid()." is writing! now count is: $count ".PHP_EOL;
     
        //释放信号量
        sem_release($signal);
        exit("child process".getmypid()."end".PHP_EOL);
      } else {
        $child_list[] = $pid;
      }
    }
     
    while (count($child_list) > 0) {
      foreach ($child_list as $key => $pid) {
        $status = pcntl_waitpid($pid, $status);
        if ($status > 0 || $status == -1) {
          unset($child_list[$key]);
        }
      }
      sleep(1);
    }
     
    $count = shm_get_var($shm_id, SHARE_KEY);
    echo " $count  ".PHP_EOL;
     
    //销毁信号量
    sem_remove($signal);
     
    shm_remove($shm_id);
    shm_detach($shm_id);

    实际运用中根据场景灵活运用就可以了~

  • 相关阅读:
    python对于相同值的内存管理
    python的in,is和id函数
    sublime text3格式化json,格式化sql代码
    VMware15.5版本安装CentOS7
    VMware15.5版本安装Windows_Server_2008_R2
    MySQL事务
    判定表组成法
    正交试验设计
    因果图法
    错误推测法
  • 原文地址:https://www.cnblogs.com/wt645631686/p/9145322.html
Copyright © 2011-2022 走看看