鎖,這個(gè)詞我們并不陌生,主要的應(yīng)用場(chǎng)景會(huì)發(fā)生在高并發(fā)下進(jìn)行鎖。今天的這篇文章咱們主要來(lái)講解一下swoole的鎖的機(jī)制,swoole_lock是如何實(shí)現(xiàn)的。
swoole_lock類支持5種鎖的類型:
- 文件鎖 SWOOLE_FILELOCK
- 讀寫(xiě)鎖 SWOOLE_RWLOCK
- 信號(hào)量 SWOOLE_SEM
- 互斥鎖 SWOOLE_MUTEX
- 自旋鎖 SWOOLE_SPINLOCK
創(chuàng)建這些鎖的過(guò)程其實(shí)就是調(diào)用構(gòu)造函數(shù)的過(guò)程,調(diào)用的形式如下:
swoole_lock->__construct(int $type, [string $lockfile])
$type為鎖的類型
$lockfile,當(dāng)類型為SWOOLE_FILELOCK時(shí)必須傳入,指定文件鎖的路徑
下面我們介紹下這個(gè)鎖的實(shí)現(xiàn)
static PHP_METHOD(swoole_lock, __construct)
{
long type = SW_MUTEX;
char *filelock;
zend_size_t filelock_len = 0;
int ret;
//解析輸入?yún)?shù),這里輸入?yún)?shù)有2個(gè),其中type表示鎖的類型,另外個(gè)參數(shù)是文件鎖時(shí)必須傳入(表示文件鎖對(duì)應(yīng)的文件路徑),其他鎖時(shí),不需要這個(gè)參數(shù)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", type, filelock, filelock_len) == FAILURE)
{
RETURN_FALSE;
}
//從內(nèi)存池申請(qǐng)鎖對(duì)象空間,這里僅僅是申請(qǐng)鎖空間
swLock *lock = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swLock));
if (lock == NULL)//申請(qǐng)空間失敗
{
zend_throw_exception(swoole_exception_class_entry_ptr, "global memory allocation failure.", SW_ERROR_MALLOC_FAIL TSRMLS_CC);
RETURN_FALSE;
}
switch(type)//按type遍歷,創(chuàng)建鎖對(duì)象
{
#ifdef HAVE_RWLOCK
case SW_RWLOCK://如果是讀寫(xiě)鎖
ret = swRWLock_create(lock, 1);//創(chuàng)建鎖對(duì)象,類型為讀寫(xiě)鎖
break;
#endif
case SW_FILELOCK://如果是文件鎖
if (filelock_len = 0)//第二個(gè)參數(shù)有效性檢查
{
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) //調(diào)用linux函數(shù)open,打開(kāi)文件(不存在則創(chuàng)建)
{
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);//創(chuàng)建鎖對(duì)象,類型為文件鎖
break;
case SW_SEM:
ret = swSem_create(lock, IPC_PRIVATE);//創(chuàng)建鎖對(duì)象,類型為信號(hào)量
break;
#ifdef HAVE_SPINLOCK
case SW_SPINLOCK:
ret = swSpinLock_create(lock, 1);//創(chuàng)建鎖對(duì)象,類型為樂(lè)觀鎖
break;
#endif
case SW_MUTEX:
default:
ret = swMutex_create(lock, 1);//創(chuàng)建鎖對(duì)象,類型為互斥量
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側(cè)的對(duì)象和swoole內(nèi)部對(duì)象關(guān)聯(lián)
RETURN_TRUE;
}
以下分別介紹下各個(gè)不同鎖對(duì)象的創(chuàng)建過(guò)程。
1、讀寫(xiě)鎖
int swRWLock_create(swLock *lock, int use_in_process)
{
int ret;
bzero(lock, sizeof(swLock));//鎖空間初始化
lock->type = SW_RWLOCK;//設(shè)置鎖的類型為讀寫(xiě)鎖
pthread_rwlockattr_init(lock->object.rwlock.attr);//linux函數(shù),鎖屬性信息初始化
if (use_in_process == 1)//標(biāo)記為在進(jìn)程中使用,這里pthread開(kāi)頭的linux函數(shù)默認(rèn)都是針對(duì)線程的
{
//設(shè)置鎖的屬性信息,標(biāo)記為在進(jìn)程中使用
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函數(shù),鎖信息初始化
{
return SW_ERR;
}
/*
* 設(shè)置鎖的回調(diào)函數(shù)
*/
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));//鎖對(duì)象信息初始化
lock->type = SW_FILELOCK;//設(shè)置鎖的類型為文件鎖
/*
* 設(shè)置鎖的回調(diào)函數(shù)
*/
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、信號(hào)量鎖
int swSem_create(swLock *lock, key_t key)
{
int ret;
lock->type = SW_SEM;//設(shè)置鎖類型為信號(hào)量鎖
if ((ret = semget(key, 1, IPC_CREAT | 0666)) 0)//創(chuàng)建信號(hào)量,這里設(shè)置的屬性IPC_CREAT,這表示這種信號(hào)量只能用于有親緣關(guān)系的進(jìn)程間
{
return SW_ERR;
}
if (semctl(ret, 0, SETVAL, 1) == -1)//設(shè)置信號(hào)量ret的值為1
{
swWarn("semctl(SETVAL) failed");
return SW_ERR;
}
lock->object.sem.semid = ret;//設(shè)置信號(hào)量ID
/*
* 設(shè)置回調(diào)函數(shù)
*/
lock->lock = swSem_lock;
lock->unlock = swSem_unlock;
lock->free = swSem_free;
return SW_OK;
}
4、樂(lè)觀鎖
int swSpinLock_create(swLock *lock, int use_in_process)
{
int ret;
bzero(lock, sizeof(swLock));//初始化鎖對(duì)象
lock->type = SW_SPINLOCK;//設(shè)置鎖的類型為樂(lè)觀鎖
//執(zhí)行鎖的初始化操作,這里指明是在多進(jìn)程中使用
if ((ret = pthread_spin_init(lock->object.spinlock.lock_t, use_in_process)) 0)
{
return -1;
}
/*
* 設(shè)置回調(diào)函數(shù)信息
*/
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;
}
到此這篇關(guān)于swoole鎖的機(jī)制代碼實(shí)例講解的文章就介紹到這了,更多相關(guān)swoole鎖的機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- 詳解PHP Swoole與TCP三次握手
- Swoole擴(kuò)展的6種模式深入詳解
- php中Swoole的熱更新實(shí)現(xiàn)代碼實(shí)例
- windows系統(tǒng)php環(huán)境安裝swoole具體步驟
- linux系統(tǒng)虛擬主機(jī)開(kāi)啟支持Swoole Loader擴(kuò)展的方法
- Swoole源碼中如何查詢Websocket的連接問(wèn)題詳解
- 在Windows系統(tǒng)上安裝Cygwin搭建Swoole測(cè)試環(huán)境的圖文教程
- php使用goto實(shí)現(xiàn)自動(dòng)重啟swoole、reactphp、workerman服務(wù)的代碼
- Centos7安裝swoole擴(kuò)展操作示例
- 詳解Swoole TCP流數(shù)據(jù)邊界問(wèn)題解決方案