swoole锁的机制代码实例讲解


Posted in PHP onMarch 04, 2021

锁,这个词我们并不陌生,主要的应用场景会发生在高并发下进行锁。今天的这篇文章咱们主要来讲解一下swoole的锁的机制,swoole_lock是如何实现的。

swoole_lock类支持5种锁的类型:

  • 文件锁 SWOOLE_FILELOCK
  • 读写锁 SWOOLE_RWLOCK
  • 信号量 SWOOLE_SEM
  • 互斥锁 SWOOLE_MUTEX
  • 自旋锁 SWOOLE_SPINLOCK

创建这些锁的过程其实就是调用构造函数的过程,调用的形式如下:

swoole_lock->__construct(int $type, [string $lockfile])

$type为锁的类型

$lockfile,当类型为SWOOLE_FILELOCK时必须传入,指定文件锁的路径

下面我们介绍下这个锁的实现

static PHP_METHOD(swoole_lock, __construct)
{
    long type = SW_MUTEX;
    char *filelock;
    zend_size_t filelock_len = 0;
    int ret;
    //解析输入参数,这里输入参数有2个,其中type表示锁的类型,另外个参数是文件锁时必须传入(表示文件锁对应的文件路径),其他锁时,不需要这个参数
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &type, &filelock, &filelock_len) == FAILURE)
    {
        RETURN_FALSE;
    }
    //从内存池申请锁对象空间,这里仅仅是申请锁空间
    swLock *lock = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swLock));
    if (lock == NULL)//申请空间失败
    {
        zend_throw_exception(swoole_exception_class_entry_ptr, "global memory allocation failure.", SW_ERROR_MALLOC_FAIL TSRMLS_CC);
        RETURN_FALSE;
    }
 
    switch(type)//按type遍历,创建锁对象
    {
#ifdef HAVE_RWLOCK
    case SW_RWLOCK://如果是读写锁
        ret = swRWLock_create(lock, 1);//创建锁对象,类型为读写锁
        break;
#endif
    case SW_FILELOCK://如果是文件锁
        if (filelock_len <= 0)//第二个参数有效性检查
        {
            zend_throw_exception(swoole_exception_class_entry_ptr, "filelock requires file name of the lock.", SW_ERROR_INVALID_PARAMS TSRMLS_CC);
            RETURN_FALSE;
        }
        int fd;
        if ((fd = open(filelock, O_RDWR | O_CREAT, 0666)) < 0) //调用linux函数open,打开文件(不存在则创建)
        {
            zend_throw_exception_ex(swoole_exception_class_entry_ptr, errno TSRMLS_CC, "open file[%s] failed. Error: %s [%d]", filelock, strerror(errno), errno);
            RETURN_FALSE;
        }
        ret = swFileLock_create(lock, fd);//创建锁对象,类型为文件锁
        break;
    case SW_SEM:
        ret = swSem_create(lock, IPC_PRIVATE);//创建锁对象,类型为信号量
        break;
#ifdef HAVE_SPINLOCK
    case SW_SPINLOCK:
        ret = swSpinLock_create(lock, 1);//创建锁对象,类型为乐观锁
        break;
#endif
    case SW_MUTEX:
    default:
        ret = swMutex_create(lock, 1);//创建锁对象,类型为互斥量
        break;
    }
    if (ret < 0)
    {
        zend_throw_exception(swoole_exception_class_entry_ptr, "failed to create lock.", errno TSRMLS_CC);
        RETURN_FALSE;
    }
    swoole_set_object(getThis(), lock);//PHP侧的对象和swoole内部对象关联
    RETURN_TRUE;
}

以下分别介绍下各个不同锁对象的创建过程。

1、读写锁

int swRWLock_create(swLock *lock, int use_in_process)
{
    int ret;
    bzero(lock, sizeof(swLock));//锁空间初始化
    lock->type = SW_RWLOCK;//设置锁的类型为读写锁
    pthread_rwlockattr_init(&lock->object.rwlock.attr);//linux函数,锁属性信息初始化
    if (use_in_process == 1)//标记为在进程中使用,这里pthread开头的linux函数默认都是针对线程的
    {
        //设置锁的属性信息,标记为在进程中使用
        pthread_rwlockattr_setpshared(&lock->object.rwlock.attr, PTHREAD_PROCESS_SHARED);
    }
 
    if ((ret = pthread_rwlock_init(&lock->object.rwlock._lock, &lock->object.rwlock.attr)) < 0)//linux函数,锁信息初始化
    {
        return SW_ERR;
    }
 
    /*
     * 设置锁的回调函数
     */
    lock->lock_rd = swRWLock_lock_rd;
    lock->lock = swRWLock_lock_rw;
    lock->unlock = swRWLock_unlock;
    lock->trylock = swRWLock_trylock_rw;
    lock->trylock_rd = swRWLock_trylock_rd;
    lock->free = swRWLock_free;
    return SW_OK;
}

2、文件锁。

int swFileLock_create(swLock *lock, int fd)
{
    bzero(lock, sizeof(swLock));//锁对象信息初始化
    lock->type = SW_FILELOCK;//设置锁的类型为文件锁
 
    /*
     * 设置锁的回调函数
     */
    lock->object.filelock.fd = fd;
    lock->lock_rd = swFileLock_lock_rd;
    lock->lock = swFileLock_lock_rw;
    lock->trylock_rd = swFileLock_trylock_rd;
    lock->trylock = swFileLock_trylock_rw;
    lock->unlock = swFileLock_unlock;
    lock->free = swFileLock_free;
    return 0;
}

3、信号量锁

int swSem_create(swLock *lock, key_t key)
{
    int ret;
    lock->type = SW_SEM;//设置锁类型为信号量锁
    if ((ret = semget(key, 1, IPC_CREAT | 0666)) < 0)//创建信号量,这里设置的属性IPC_CREAT,这表示这种信号量只能用于有亲缘关系的进程间
    {
        return SW_ERR;
    }
 
    if (semctl(ret, 0, SETVAL, 1) == -1)//设置信号量ret的值为1
    {
        swWarn("semctl(SETVAL) failed");
        return SW_ERR;
    }
    lock->object.sem.semid = ret;//设置信号量ID
 
    /*
     * 设置回调函数
     */
    lock->lock = swSem_lock;
    lock->unlock = swSem_unlock;
    lock->free = swSem_free;
 
    return SW_OK;
}

4、乐观锁

int swSpinLock_create(swLock *lock, int use_in_process)
{
    int ret;
    bzero(lock, sizeof(swLock));//初始化锁对象
    lock->type = SW_SPINLOCK;//设置锁的类型为乐观锁
    //执行锁的初始化操作,这里指明是在多进程中使用
    if ((ret = pthread_spin_init(&lock->object.spinlock.lock_t, use_in_process)) < 0)
    {
        return -1;
    }
 
    /*
     * 设置回调函数信息
     */
    lock->lock = swSpinLock_lock;
    lock->unlock = swSpinLock_unlock;
    lock->trylock = swSpinLock_trylock;
    lock->free = swSpinLock_free;
    return 0;
}

5、互斥量锁

int swMutex_create(swLock *lock, int use_in_process)
{
    int ret;
    bzero(lock, sizeof(swLock));
    lock->type = SW_MUTEX;
    pthread_mutexattr_init(&lock->object.mutex.attr);
    if (use_in_process == 1)
    {
        pthread_mutexattr_setpshared(&lock->object.mutex.attr, PTHREAD_PROCESS_SHARED);
    }
    if ((ret = pthread_mutex_init(&lock->object.mutex._lock, &lock->object.mutex.attr)) < 0)
    {
        return SW_ERR;
    }
    lock->lock = swMutex_lock;
    lock->unlock = swMutex_unlock;
    lock->trylock = swMutex_trylock;
    lock->free = swMutex_free;
    return SW_OK;
}

到此这篇关于swoole锁的机制代码实例讲解的文章就介绍到这了,更多相关swoole锁的机制内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
PHP5中新增stdClass 内部保留类
Jun 13 PHP
php5.5中类级别的常量使用介绍
Oct 02 PHP
php+mysql大量用户登录解决方案分析
Dec 29 PHP
PHP中使用php://input处理相同name值的表单数据
Feb 03 PHP
如何用PHP来实现一个动态Web服务器
Jul 29 PHP
PHP加密解密类实例代码
Jul 20 PHP
简单实现php上传文件功能
Sep 21 PHP
php统计数组不同元素的个数的实例方法
Sep 26 PHP
PHP框架实现WebSocket在线聊天通讯系统
Nov 21 PHP
PHP获取当前时间不准确问题解决方案
Aug 14 PHP
PHP SESSION跨页面传递失败解决方案
Dec 11 PHP
你真的了解PHP中的引用符号(&)吗
May 12 PHP
PHP实现chrome表单请求数据转换为接口使用的json数据
Mar 04 #PHP
windows系统php环境安装swoole具体步骤
Mar 04 #PHP
php中使用array_filter()函数过滤数组实例讲解
Mar 03 #PHP
php array_map()函数实例用法
Mar 03 #PHP
PHP的imageTtfText()函数深入详解
Mar 03 #PHP
PHP实现爬虫爬取图片代码实例
Mar 03 #PHP
PHP执行系统命令函数实例讲解
Mar 03 #PHP
You might like
PL-880隐藏功能
2021/03/01 无线电
PHP学习笔记之数组篇
2011/06/28 PHP
PHP中使用json数据格式定义字面量对象的方法
2014/08/20 PHP
PHP 7.0新增加的特性介绍
2017/06/08 PHP
php实现session共享的实例方法
2019/09/19 PHP
浅析PHP反序列化中过滤函数使用不当导致的对象注入问题
2020/02/15 PHP
jQeury淡入淡出需要注意的问题
2010/09/08 Javascript
xmlhttp缓存清除的2种解决方法
2013/12/13 Javascript
用javascript关闭本窗口技巧小结
2014/09/05 Javascript
Python脚本后台运行的几种方式
2015/03/09 Javascript
Bootstrap项目实战之子栏目资讯内容
2016/04/25 Javascript
JavaScript必知必会(二) null 和undefined
2016/06/08 Javascript
JS使用正则截取两个字符串之间的字符串实现方法详解
2017/01/06 Javascript
深入理解vue.js中的v-if和v-show
2017/06/22 Javascript
JavaScript中使用参数个数实现重载功能
2017/09/01 Javascript
jQuery实现的简单手风琴效果示例
2018/08/29 jQuery
vue2.0 可折叠列表 v-for循环展示的实例
2018/09/07 Javascript
Nuxt.js 数据双向绑定的实现
2019/02/17 Javascript
js中forEach,for in,for of循环的用法示例小结
2020/03/14 Javascript
JavaScript oncopy事件用法实例解析
2020/05/13 Javascript
在Python的Flask框架下收发电子邮件的教程
2015/04/21 Python
简单谈谈python的反射机制
2016/06/28 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
Numpy一维线性插值函数的用法
2020/04/22 Python
中国汽车租赁行业头部企业:一嗨租车
2019/05/16 全球购物
请问如下代码执行后a和b的值分别是什么
2016/05/05 面试题
一道SQL存储过程面试题
2016/10/07 面试题
正隆泰信息技术有限公司上机题
2012/06/14 面试题
商务英语专业自荐信
2013/10/14 职场文书
业务助理岗位职责
2013/11/18 职场文书
建筑施工员岗位职责
2013/11/26 职场文书
管理站站长岗位职责
2013/11/27 职场文书
竞职演讲稿范文
2014/01/11 职场文书
学校党员个人问题整改措施思想汇报
2014/10/08 职场文书
建立共青团委员会的请示
2019/04/02 职场文书
apache基于端口创建虚拟主机的示例
2021/04/22 Servers