您好,登錄后才能下訂單哦!
基于linux threads2.0.1線程源碼如何分析信號(hào)量,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
/* Semaphores a la POSIX 1003.1b */
#include "pthread.h"
#include "semaphore.h"
#include "internals.h"
#include "restart.h"
#ifndef HAS_COMPARE_AND_SWAP
/* If we have no atomic compare and swap, fake it using an extra spinlock. */
#include "spinlock.h"
// 等于舊值則更新sem_status為新值,如果一樣則不更新,更新則返回1
static inline int compare_and_swap(sem_t *sem, long oldval, long newval)
{
int ret;
acquire(&sem->sem_spinlock);
if ((ret = sem->sem_status == oldval) != 0)
sem->sem_status = newval;
release(&sem->sem_spinlock);
return ret;
}
#else
/* But if we do have an atomic compare and swap, use it! */
#define compare_and_swap(sem,old,new) \
__compare_and_swap(&(sem)->sem_status, (old), (new))
#endif
/* The state of a semaphore is represented by a long int encoding
either the semaphore count if >= 0 and no thread is waiting on it,
or the head of the list of threads waiting for the semaphore.
To distinguish the two cases, we encode the semaphore count N
as 2N+1, so that it has the lowest bit set.
A sequence of sem_wait operations on a semaphore initialized to N
result in the following successive states:
2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ...
*/
int sem_init(sem_t *sem, int pshared, unsigned int value)
{
if (value > SEM_VALUE_MAX) {
errno = EINVAL;
return -1;
}
// 還沒實(shí)現(xiàn)
if (pshared) {
errno = ENOSYS;
return -1;
}
// 記錄資源數(shù)
sem->sem_status = ((long)value << 1) + 1;
return 0;
}
int sem_wait(sem_t * sem)
{
long oldstatus, newstatus;
volatile pthread_t self = thread_self();
pthread_t * th;
while (1) {
do {
// oldstatus可能是線程或者資源數(shù)
oldstatus = sem->sem_status;
// 大于1說明有資源,等于1說著0說明沒有資源或沒有資源并且有線程阻塞
if ((oldstatus & 1) && (oldstatus != 1))
newstatus = oldstatus - 2;
else {
// 沒有可用資源,需要阻塞
newstatus = (long) self;
// 保存這時(shí)候的資源數(shù)或者上一個(gè)被阻塞的線程
self->p_nextwaiting = (pthread_t) oldstatus;
}
}
// sem_status可能指向資源數(shù)或者被阻塞的線程鏈表。賦值成功則返回1,否則返回0
while (! compare_and_swap(sem, oldstatus, newstatus));
// self是按偶數(shù)地址對(duì)齊的,低位為1說明是還有可用資源
if (newstatus & 1)
/* We got the semaphore. */
return 0;
/* Wait for sem_post or cancellation */
// 等待被restart或者cancel信號(hào)喚醒
suspend_with_cancellation(self);
/* This is a cancellation point */
// 判斷是否被取消了,即是被cancel信號(hào)喚醒的,不是的話重新判斷是否有資源,即回到上面的while(1)
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
/* Remove ourselves from the waiting list if we're still on it */
/* First check if we're at the head of the list. */
do {
// 得到被阻塞的第一個(gè)線程
oldstatus = sem->sem_status;
// 相等說明當(dāng)前線程是最后一個(gè)被阻塞的線程
if (oldstatus != (long) self) break;
// 得到該線程被阻塞時(shí)的資源數(shù)或下一個(gè)被阻塞的線程
newstatus = (long) self->p_nextwaiting;
}
// sem_status指向資源數(shù)或者下一個(gè)被阻塞的線程
while (! compare_and_swap(sem, oldstatus, newstatus));
/* Now, check if we're somewhere in the list.
There's a race condition with sem_post here, but it does not matter:
the net result is that at the time pthread_exit is called,
self is no longer reachable from sem->sem_status. */
// 可能是break或者while為true,不是當(dāng)前線程并且不是資源數(shù),即oldstatus指向一個(gè)其他線程
if (oldstatus != (long) self && (oldstatus & 1) == 0) {
th = &(((pthread_t) oldstatus)->p_nextwaiting);
// 不是資源數(shù),即是線程,從等待的線程鏈表中刪除self線程,因?yàn)樗磳⑼顺?br/> while (*th != (pthread_t) 1 && *th != NULL) {
if (*th == self) {
*th = self->p_nextwaiting;
break;
}
th = &((*th)->p_nextwaiting);
}
}
// 當(dāng)前線程退出
pthread_exit(PTHREAD_CANCELED);
}
}
}
// 非阻塞獲取信號(hào)量
int sem_trywait(sem_t * sem)
{
long oldstatus, newstatus;
do {
oldstatus = sem->sem_status;
// oldstatus & 1等于0說明是線程,即有線程在等待,或者等于1,都說明沒有可用資源,直接返回
if ((oldstatus & 1) == 0 || (oldstatus == 1)) {
errno = EAGAIN;
return -1;
}
// 更新資源數(shù)
newstatus = oldstatus - 2;
}
// 更新資源數(shù),如果失敗說明被其他線程拿到鎖了,則重新執(zhí)行do里面的邏輯,因?yàn)閿?shù)據(jù)可能被修改了
while (! compare_and_swap(sem, oldstatus, newstatus));
return 0;
}
int sem_post(sem_t * sem)
{
long oldstatus, newstatus;
pthread_t th, next_th;
do {
oldstatus = sem->sem_status;
// 說明原來的資源數(shù)是0,并且有線程在等待,則更新為1,2n+1即3
if ((oldstatus & 1) == 0)
newstatus = 3;
else {
if (oldstatus >= SEM_VALUE_MAX) {
/* Overflow */
errno = ERANGE;
return -1;
}
// 否則加2,即資源數(shù)加一
newstatus = oldstatus + 2;
}
}
// 更新資源數(shù)
while (! compare_and_swap(sem, oldstatus, newstatus));
// 如果之前有線程阻塞,則喚醒所有線程,再次競(jìng)爭(zhēng)獲得信號(hào)量
if ((oldstatus & 1) == 0) {
th = (pthread_t) oldstatus;
do {
next_th = th->p_nextwaiting;
th->p_nextwaiting = NULL;
restart(th);
th = next_th;
} while(th != (pthread_t) 1);
}
return 0;
}
// 獲取資源數(shù)
int sem_getvalue(sem_t * sem, int * sval)
{
long status = sem->sem_status;
// 有資源
if (status & 1)
// 除以2
*sval = (int)((unsigned long) status >> 1);
else
*sval = 0;
return 0;
}
int sem_destroy(sem_t * sem)
{
// 有線程在等待
if ((sem->sem_status & 1) == 0) {
errno = EBUSY;
return -1;
}
return 0;
}
阻塞時(shí)的視圖。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。