溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于linux threads2.0.1線程源碼如何分析信號(hào)量

發(fā)布時(shí)間:2021-12-09 09:29:56 來源:億速云 閱讀:149 作者:柒染 欄目:大數(shù)據(jù)

基于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;
}

             

基于linux threads2.0.1線程源碼如何分析信號(hào)量

阻塞時(shí)的視圖。

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問一下細(xì)節(jié)

免責(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)容。

AI