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 相关文章推荐
MySql中正则表达式的使用方法描述
Jul 30 PHP
很好用的PHP数据库类
May 27 PHP
解析PHP自带的进位制之间的转换函数
Jun 08 PHP
PHP版 汉字转码的实现详解
Jun 09 PHP
微信支付开发教程(一)微信支付URL配置
May 28 PHP
一个简洁实用的PHP缓存类完整实例
Jul 26 PHP
php给每个段落添加空格的方法
Mar 20 PHP
php实现购物车功能(下)
Jan 05 PHP
postman的安装与使用方法(模拟Get和Post请求)
Aug 06 PHP
php操作mongodb封装类与用法实例
Sep 01 PHP
php根据地址获取百度地图经纬度的实例方法
Sep 03 PHP
php+iframe 实现上传文件功能示例
Mar 04 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
Zerg基本策略
2020/03/14 星际争霸
解析mysql中UNIX_TIMESTAMP()函数与php中time()函数的区别
2013/06/24 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
分享php分页的功能模块
2015/06/16 PHP
PHP 表单提交及处理表单数据详解及实例
2016/12/27 PHP
PHP 实现从数据库导出到.csv文件方法
2017/07/06 PHP
javascript实现数字倒计时特效
2016/03/30 Javascript
概述jQuery中的ajax方法
2016/12/16 Javascript
JS奇技之利用scroll来监听resize详解
2017/06/15 Javascript
JavaScript文件的同步和异步加载的实现代码
2017/08/19 Javascript
JavaScript使用Math.random()生成简单的验证码
2019/01/21 Javascript
解决Vue @submit 提交后不刷新页面问题
2020/07/18 Javascript
vue实现单一筛选、删除筛选条件
2020/10/26 Javascript
[01:38]DOTA2辉夜杯 欢乐的观众现场采访
2015/12/26 DOTA
[01:00:49]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第二场 1月31日
2021/03/11 DOTA
python实现分页效果
2017/10/25 Python
Python 数据处理库 pandas进阶教程
2018/04/21 Python
django+xadmin+djcelery实现后台管理定时任务
2018/08/14 Python
Python学习笔记之自定义函数用法详解
2019/06/08 Python
Python 获取windows桌面路径的5种方法小结
2019/07/15 Python
Python实现PyPDF2处理PDF文件的方法示例
2019/09/25 Python
python运用sklearn实现KNN分类算法
2019/10/16 Python
python给指定csv表格中的联系人群发邮件(带附件的邮件)
2019/12/31 Python
Python实现名片管理系统
2020/02/14 Python
Keras预训练的ImageNet模型实现分类操作
2020/07/07 Python
使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二)
2020/10/12 Python
Pure Collection美国官网:来自英国羊绒专家的奢华羊绒
2017/11/19 全球购物
一套VC试题
2015/01/23 面试题
结婚邀请函范文
2014/01/14 职场文书
店面出租协议书范本
2014/11/28 职场文书
师德标兵先进事迹材料
2014/12/19 职场文书
离婚协议书范文2016
2016/03/18 职场文书
导游词之山东八大关
2019/12/18 职场文书
使用numpy nonzero 找出非0元素
2021/05/14 Python
分享Python获取本机IP地址的几种方法
2022/03/17 Python
MySQL如何修改字段类型和字段长度
2022/06/10 MySQL