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版(3)
Oct 09 PHP
PHP+DBM的同学录程序(1)
Oct 09 PHP
用PHP和ACCESS写聊天室(十)
Oct 09 PHP
一个PHP数组应该有多大的分析
Jul 30 PHP
PHP迅雷、快车、旋风下载专用链转换代码
Jun 15 PHP
php 获取百度的热词数据的代码
Feb 18 PHP
PHP学习笔记(三):数据类型转换与常量介绍
Apr 17 PHP
PHP pear安装配置教程
May 14 PHP
php中Redis的应用--消息传递
Mar 28 PHP
CI框架网页缓存简单用法分析
Dec 26 PHP
PHP SESSION机制的理解与实例
Mar 22 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
Aug 03 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
虹吸壶是谁发明的?煮出来的咖啡好喝吗
2021/03/04 冲泡冲煮
实现树状结构的两种方法
2006/10/09 PHP
PHP和Mysqlweb应用开发核心技术-第1部分 Php基础-2 php语言介绍
2011/07/03 PHP
利用PHP函数计算中英文字符串长度的方法
2014/11/11 PHP
js基于qrcode.js生成二维码的方法【附demo插件源码下载】
2016/12/28 PHP
PHP实现数组向任意位置插入,删除,替换数据操作示例
2019/04/05 PHP
PHP实现爬虫爬取图片代码实例
2021/03/03 PHP
js 深拷贝函数
2008/12/04 Javascript
模仿JQuery sortable效果 代码有错但值得看看
2009/11/05 Javascript
js实现浏览器窗口大小被改变时触发事件的方法
2015/02/02 Javascript
javascript跨域原因以及解决方案分享
2015/04/08 Javascript
深入解析JavaScript编程中的this关键字使用
2015/11/09 Javascript
AngularJs入门教程之环境搭建+创建应用示例
2016/11/01 Javascript
angular directive的简单使用总结
2017/05/24 Javascript
Vue动态实现评分效果
2017/05/24 Javascript
原生js FileReader对象实现图片上传本地预览效果
2020/03/27 Javascript
关于Angularjs中跨域设置白名单问题
2018/04/17 Javascript
详解如何制作并发布一个vue的组件的npm包
2018/11/10 Javascript
自定义Vue中的v-module双向绑定的实现
2019/04/17 Javascript
配置一个vue3.0项目的完整步骤
2019/04/26 Javascript
详解 微信小程序开发框架(MINA)
2019/05/17 Javascript
JavaScript实现图片轮播特效
2019/10/23 Javascript
vue打包静态资源后显示空白及static文件路径报错的解决
2020/09/02 Javascript
Python基于pygame实现图片代替鼠标移动效果
2015/11/11 Python
pytorch在fintune时将sequential中的层输出方法,以vgg为例
2019/08/20 Python
Python While循环语句实例演示及原理解析
2020/01/03 Python
python向企业微信发送文字和图片消息的示例
2020/09/28 Python
英国电视和家用电器购物网站:rlrdistribution.co.uk
2018/11/20 全球购物
mysql_pconnect()和mysql_connect()有什么区别
2012/05/25 面试题
材料化学应届生求职信
2013/10/09 职场文书
宿舍违规检讨书
2014/01/12 职场文书
料理师求职信
2014/01/30 职场文书
幼儿园小班教师寄语
2014/04/03 职场文书
美术第二课堂活动总结
2014/07/08 职场文书
创业者如何撰写出一份打动投资人的商业计划书?
2019/07/02 职场文书
mysql 子查询的使用
2022/04/28 MySQL