簡體   English   中英

為什么在glibc的NPTL實現中訪問pthread密鑰的序列號不同步?

[英]Why accessing pthread keys' sequence number is not synchronized in glibc's NPTL implementation?

最近,當我研究如何在glibc中實現線程本地存儲時,發現了以下代碼,該代碼實現了API pthread_key_create()

int
__pthread_key_create (key, destr)
      pthread_key_t *key;
      void (*destr) (void *);
{
    /* Find a slot in __pthread_kyes which is unused.  */
    for (size_t cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt)
    {
        uintptr_t seq = __pthread_keys[cnt].seq;

        if (KEY_UNUSED (seq) && KEY_USABLE (seq)
            /* We found an unused slot.  Try to allocate it.  */
            && ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[cnt].seq,
                                                       seq + 1, seq))
        {
            /* Remember the destructor.  */
            __pthread_keys[cnt].destr = destr;

            /* Return the key to the caller.  */
            *key = cnt;

            /* The call succeeded.  */
            return 0;
       }
    }

    return EAGAIN;
}

__pthread_keys是所有線程訪問的全局數組。 我不明白為什么其成員seq的讀取不同步,如下所示:

uintptr_t seq = __pthread_keys[cnt].seq;

盡管稍后修改它已同步。

僅供參考, __pthread_keys struct pthread_key_struct是類型為struct pthread_key_struct的數組,其定義如下:

/* Thread-local data handling.  */
struct pthread_key_struct
{
    /* Sequence numbers.  Even numbers indicated vacant entries.  Note
       that zero is even.  We use uintptr_t to not require padding on
       32- and 64-bit machines.  On 64-bit machines it helps to avoid
       wrapping, too.  */
    uintptr_t seq;

    /* Destructor for the data.  */
    void (*destr) (void *);
};

提前致謝。

在這種情況下,循環可以避免昂貴的鎖獲取。 稍后執行的原子比較和交換操作atomic_compare_and_exchange_bool_acq )將確保只有一個線程可以成功遞增序列值並將鍵返回給調用方。 第一步中其他讀取相同值的線程將繼續循環,因為CAS僅對單個線程成功。

這是有效的,因為序列值在偶數(空)和奇數(已占用)之間交替。 將該值遞增為奇數可防止其他線程獲取該插槽。

通常,僅讀取值比CAS指令要少一些周期,因此在執行CAS之前先查看一下值是有意義的。

有許多利用CAS指令實現低開銷同步的免等待和無鎖算法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM