Atomic 是 Swoole 底层提供的原子计数操作类,可以方便整数的无锁原子增减。原子计数器有如下特点:

- 使用共享内存,可以在不同的进程之间操作计数

- 基于 gcc/clang 提供的 CPU 原子指令,无需加锁

- 在服务器程序中必须在 Server->start 前创建才能在 Worker 进程中使用

- 默认使用 32 位无符号类型,如需要 64 有符号整型,可使用 Swoole\Atomic\Long

注意:

- 请勿在 onReceive 等回调函数中创建计数器,否则内存会持续增长,造成内存泄漏。

- 支持 64 位有符号长整型原子计数,需要使用 new Swoole\Atomic\Long 来创建。Atomic\Long 不支持 wait 和 wakeup 方法。

完整代码示例:

$atomic = new Swoole\Atomic();

$serv = new Swoole\Server('127.0.0.1', '9501');
$serv->set([
'worker_num' => 1,
'log_file' => '/dev/null'
]);
$serv->on("start", function ($serv) use ($atomic) {
if ($atomic->add() == 2) {
$serv->shutdown();
}
});
$serv->on("ManagerStart", function ($serv) use ($atomic) {
if ($atomic->add() == 2) {
$serv->shutdown();
}
});
$serv->on("ManagerStop", function ($serv) {
echo "shutdown\n";
});
$serv->on("Receive", function () { });
$serv->start();

成员函数

1) __construct():构造函数。创建一个原子计数对象。

Swoole\Atomic::__construct(int $init_value = 0);

$init_value:指定初始化的数值

注意:

- Atomic 只能操作 32 位无符号整数,最大支持 42 亿,不支持负数;

- 在 Server 中使用原子计数器,必须在 Server->start 前创建;

- 在 Process 中使用原子计数器,必须在 Process->start 前创建。

2) add():增加计数

Swoole\Atomic->add(int $add_value = 1): int

$add_value:要增加的数值【必须为正整数】

返回值:add 方法操作成功后返回结果数值

注意:与原值相加如果超过 42 亿,将会溢出,高位数值会被丢弃。

3) sub():减少计数

Swoole\Atomic->sub(int $sub_value = 1): int

$sub_value:要减少的数值【必须为正整数】

返回值:sub 方法操作成功后返回结果数值

注意:与原值相减如果低于 0 将会溢出,高位数值会被丢弃。

4) get():获取当前计数的值

Swoole\Atomic->get(): int

返回值:返回当前的数值

5) set():将当前值设置为指定的数字。

Swoole\Atomic->set(int $value): void

$value:指定要设置的目标数值

6) compset():如果当前数值等于参数 1,则将当前数值设置为参数 2。

Swoole\Atomic->cmpset(int $cmp_value, int $set_value): bool

$cmp_value:如果当前数值等于 $cmp_value 返回 true,并将当前数值设置为 $set_value,如果不等于返回 false【必须为小于 42 亿的整数】

$set_value:如果当前数值等于 $cmp_value 返回 true,并将当前数值设置为 $set_value,如果不等于返回 false【必须为小于 42 亿的整数】

7) wait():设置为 wait 状态。

Swoole\Atomic->wait(float $timeout = 1.0): bool

$timeout:指定超时时间【设置为 -1 时表示永不超时,会持续等待直到有其他进程唤醒】,单位:秒【支持浮点型,如 1.5 表示 1s+500ms】

返回值:超时返回 false,错误码为 EAGAIN,可使用 swoole_errno 函数获取;成功返回 true,表示有其他进程通过 wakeup 成功唤醒了当前的锁

注意:

- 在协程环境下,wait 会阻塞整个进程而不是协程,因此请勿在协程环境中使用 Atomic->wait() 避免引起进程挂起。

- 使用 wait/wakeup 特性时,原子计数的值只能为 0 或 1,否则会导致无法正常使用;

- 当然原子计数的值为 1 时,表示不需要进入等待状态,资源当前就是可用。wait 函数会立即返回 true。

说明:当原子计数的值为 0 时程序进入等待状态。另外一个进程调用 wakeup 可以再次唤醒程序。底层基于 Linux Futex 实现,使用此特性,可以仅用 4 字节内存实现一个等待、通知、锁的功能。在不支持 Futex 的平台下,底层会使用循环 usleep(1000) 模拟实现。

示例:

$n = new Swoole\Atomic;
if (pcntl_fork() > 0) {
echo "master start\n";
$n->wait(1.5);
echo "master end\n";
} else {
echo "child start\n";
sleep(1);
$n->wakeup();
echo "child end\n";
}

8) wakeup():唤醒处于 wait 状态的其他进程。

Swoole\Atomic->wakeup(int $n = 1): bool

$n:唤醒的进程数量

注意:

-  当前原子计数如果为 0 时,表示没有进程正在 wait,wakeup 会立即返回 true;

-  当前原子计数如果为 1 时,表示当前有进程正在 wait,wakeup 会唤醒等待的进程,并返回 true;

-  被唤醒的进程返回后,会将原子计数设置为 0,这时可以再次调用 wakeup 唤醒其他正在 wait 的进程。

写在最后:经笔者测试,Swoole\Atomic原子操作并非完全稳定,会出现更新丢失,如下所示:

$atomic=new Swoole\Atomic();
$pool=new Swoole\Process\Pool(3,SWOOLE_IPC_NONE,0,true);
$pool->on("WorkerStart",function($pool,$worker_id) use($atomic){ Swoole\Timer::tick(1000,function() use ($atomic,$worker_id){
echo $worker_id,":",$atomic->get(),PHP_EOL;
$atomic->add(1);
}); });
$pool->on("WorkerStop",function($pool,$worker_id){
echo "$worker_id stop",PHP_EOL;
}); $pool->start();

---------------------------  我是可爱的分割线  ----------------------------

最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。

Swoole从入门到入土(25)——多进程[进程间无锁计数器]的更多相关文章

  1. Swoole 中使用 Atomic 实现进程间无锁计数器

    使用示例: $atomic = new Swoole\Atomic(); $serv = new Swoole\Server('127.0.0.1', '9501'); $serv->set([ ...

  2. pthread mutex 进程间互斥锁实例

    共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...

  3. Swoole 中使用 Table 内存表实现进程间共享数据

    背景 在多进程模式下进程之间的内存是相互隔离的,在一个工作进程中的全局变量和超全局变量,在另一个工作进程中是无法读取和操作的. 如果只有一个工作进程,则不存在进程隔离问题,可以使用全局变量和超全局变量 ...

  4. 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型

    进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...

  5. Python多进程-进程间数据的共享

    不同的进程不能同时修改一份数据,但是不同的进程能对一份数据进行修改 可通过Manager来实现进程间的数据共享 # -*- coding:utf-8 -*- __author__ = "Mu ...

  6. Python多进程-进程间数据的传递

    两个进程间的数据是独立的,要进行数据传递的话可通过几个方法 Queue 通过队列来进行进程间数据的传递 # -*- coding:utf-8 -*- __author__ = "MuT6 S ...

  7. NET多线程之进程间同步锁Mutex

    Mutex类似于lock.Monitor,都是为了解决多线程环境下,资源竞争导致的访问顺序问题.常见资源竞争有以下情况: 1.单例,如何确保单例: 2.IO文件操作,如果同时又多个线程访问同一个文件会 ...

  8. 守护进程,互斥锁,IPC,生产者与消费者模型

    守护进程: b 进程守护 a进程,当a进程执行完毕时,b进程会跟着立马结束 守护进程用途: 如果父进程结束了,子进程无需运行了,就可以将子进程设置为父进程的守护进程 例如我们qq视频聊天时,当我们退出 ...

  9. c++ 网络编程(三) LINUX/windows 进程间的通信原理与实现代码 基于多进程的服务端实现

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613027.html 锲子:进程与线程是什么,他们的区别在哪里: 1 进程概念 进程是程序的一 ...

  10. python并发编程之多进程1互斥锁与进程间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

随机推荐

  1. 【转】获取本地图片的URL

        在写博客插入图片时,许多时候需要提供图片的url地址.作为菜鸡的我,自然是一脸懵逼.那么什么是所谓的url地址呢?又该如何获取图片的url地址呢? 首先来看一下度娘对url地址的解释:url是 ...

  2. Go-使用本地时间解析时间字符串

    字符串 ==> time.Time package main import ( "fmt" "log" "time" ) func m ...

  3. IBM java的分析工具(ga和ha)学习和整理

    IBM java的分析工具(ga和ha)学习和整理 背景 前几天学习了整理了 jca 工具 今天继续学习一下 ga工具 ga 工具主要是分析gclog相关. 可以很直观的进行gclog的分析和展示. ...

  4. Navicat For Redis 的学习与使用

    Navicat For Redis 的学习与使用 背景 周末在家看了几个公众号: 说到Navicat 16.2已经有了 Redis的客户端. 想着前段时间一直在学习Redis, 但是没有GUI的工具, ...

  5. Python学习之三: 编译二进制

    Python学习之三: 编译二进制 摘要 每次使用python 执行py文件其实是比较麻烦的 主要是还得安装python的虚拟机,以及安装对应的pip包. 感觉比较繁杂 理论上最快捷的方式是编译成 二 ...

  6. [转帖]overcommit_memory、overcommit_ratio、CommitLimit、Committed_AS概念

    overcommit_memory.overcommit_ratio.CommitLimit.Committed_AS概念 overcommit_memory是一个内核对内存分配的一种策略. over ...

  7. 【解决了一个小问题】es query返回数据中, int64类型精度丢失的问题

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 首先定义了一个简单的结构体来接收es query返回的数据 ...

  8. 如何计算一个uint64类型的二进制值的尾部有多少个0

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu 公众号:一本正经的瞎扯 正文 这实在是一个很简单的问题,用代码可以表示如下: func Coun ...

  9. Gorm日志设置

    Logger Gorm提供了一个默认的logger实现,默认情况下日志数据级别为warn,同时输出慢SQL: Default = New(log.New(os.Stdout, "\r\n&q ...

  10. 基于.Net Core3.1 MVC + EF Core的项目(一)框架的初步搭建

    项目暂时分为六大块,结构如图所示 代码地址是  https://github.com/hudean/VacantCloud-   里面有许多没有完成,不过一些大致的内容都写的差不多了,权限认证依赖注入 ...