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 相关文章推荐
简单的php 验证图片生成函数
May 21 PHP
有关JSON以及JSON在PHP中的应用
Apr 09 PHP
php中Session的生成机制、回收机制和存储机制探究
Aug 19 PHP
destoon首页调用求购供应信息的地区名称的方法
Aug 21 PHP
用 Composer构建自己的 PHP 框架之构建路由
Oct 30 PHP
php生成唯一的订单函数分享
Feb 02 PHP
PHP实现微信网页授权开发教程
Jan 19 PHP
php组合排序简单实现方法
Oct 15 PHP
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
Dec 14 PHP
thinkphp修改配置进入默认首页的方法
Feb 07 PHP
利用Laravel事件系统如何实现登录日志的记录详解
May 20 PHP
PHP SFTP实现上传下载功能
Jul 26 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
PHP把小数转成整数3种方法
2014/06/30 PHP
THINKPHP支持YAML配置文件的设置方法
2015/03/17 PHP
支持中文的PHP按字符串长度分割成数组代码
2015/05/17 PHP
php+mysql开发的最简单在线题库(在线做题系统)完整案例
2019/03/30 PHP
精通Javascript系列之Javascript基础篇
2011/06/07 Javascript
基于jquery的用鼠标画出可移动的div
2012/09/06 Javascript
jQuery 追加元素的方法如append、prepend、before
2014/01/16 Javascript
js格式化时间和js格式化时间戳示例
2014/02/10 Javascript
javascript的解析执行顺序在各个浏览器中的不同
2014/03/17 Javascript
Javascript核心读书有感之类型、值和变量
2015/02/11 Javascript
使用伪命名空间封装保护独自创建的对象方法
2016/08/04 Javascript
jQuery插件之validation插件
2017/03/29 jQuery
vuejs+element-ui+laravel5.4上传文件的示例代码
2017/08/12 Javascript
Vue CLI3 开启gzip压缩文件的方式
2018/09/30 Javascript
Vue中全局变量的定义和使用
2019/06/05 Javascript
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
antd vue 刷新保留当前页面路由,保留选中菜单,保留menu选中操作
2020/08/06 Javascript
Python文件及目录操作实例详解
2015/06/04 Python
python中如何使用正则表达式的非贪婪模式示例
2017/10/09 Python
Python判断telnet通不通的实例
2019/01/26 Python
使用GitHub和Python实现持续部署的方法
2019/05/09 Python
Python 类的私有属性和私有方法实例分析
2019/09/29 Python
关于PySnooper 永远不要使用print进行调试的问题
2021/03/04 Python
完美解决IE8下不兼容rgba()的问题
2017/03/31 HTML / CSS
编程用JAVA解析XML的方式
2013/07/07 面试题
自荐信不宜过于夸大
2013/11/06 职场文书
公司庆典邀请函范文
2014/01/13 职场文书
爬山的活动方案
2014/08/16 职场文书
党的群众路线对照检查材料
2014/09/22 职场文书
店面出租协议书范本
2014/11/28 职场文书
2016优秀班主任个人先进事迹材料
2016/02/26 职场文书
详解nodejs内置模块
2021/05/06 NodeJs
html5中sharedWorker实现多页面通信的示例代码
2021/05/07 Javascript
MongoDB数据库的安装步骤
2021/06/18 MongoDB
redis requires ruby version2.2.2的解决方案
2021/07/15 Redis
vue3种table表格选项个数的控制方法
2022/04/14 Vue.js