簡體   English   中英

安全刪除並發鏈表中的節點

[英]Safe removal of a node in a concurrent linked list

我正在讀這本書APUE。 當我閱讀關於pthread reader / writer-lock的章節時,我對使用reader / writer-lock實現並發隊列有一個疑問。

struct queue {
    struct job *q_head;
    struct job *q_tail;
    pthread_rwlock_t q_lock;
};

/*
* Remove the given job from a queue.
*/
void
job_remove(struct queue *qp, struct job *jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    if (jp == qp->q_head) {
        qp->q_head = jp->j_next;
        if (qp->q_tail == jp)
            qp->q_tail = NULL;
        else
            jp->j_next->j_prev = jp->j_prev;
    } else if (jp == qp->q_tail) {
        qp->q_tail = jp->j_prev;
        jp->j_prev->j_next = jp->j_next;
    } else {
        jp->j_prev->j_next = jp->j_next;
        jp->j_next->j_prev = jp->j_prev;
    }
    pthread_rwlock_unlock(&qp->q_lock);
}

我的問題是這個實現如何確保只從鏈表中刪除一次struct job 根據我的理解,可以安排兩個線程,使它們就在pthread_rwlock_wrlock行之前。 然后struct job *jp可能會被釋放兩次。 如果struct job *是動態分配的數據結構,這可能會導致雙重錯誤。 有什么建議?

您的代碼中存在競爭條件。 其他更改可能發生在兩個線程之間的隊列中,該隊列獲取隊列上的寫鎖定,然后嘗試刪除同一節點。 可以刪除其他節點,可以添加其他節點。 因此,如果線程A刪除節點,則發生更改,然后線程B再次嘗試刪除同一節點,您的隊列可能已損壞。

代碼需要信息才能讓它知道節點已被刪除。

查看添加的注釋以及修復競爭條件的代碼:

struct queue {
    struct job *q_head;
    struct job *q_tail;
    pthread_rwlock_t q_lock;
};

/*
* Remove the given job from a queue.
*/
void
job_remove(struct queue *qp, struct job *jp)
{
    // we assume here that jp is actually in the queue
    pthread_rwlock_wrlock(&qp->q_lock);

    // at this point, jp may no longer be in the queue,
    // and in fact, the queue may be completely different.
    // thus, any modification to the queue based on the
    // assumption that jp is still part of the queue
    // can lead to corruption of the queue

    // so check if jp has been removed - we'll later set
    // both j_next and j_prev to NULL after jp is
    // removed from the queue - and if they're both
    // NULL here that means another thread already
    // removed jp from the queue
    if ( !(jp->j_next) && !(jp->j_prev) ) {
        // empty statement - jp is already removed
        ;
    }
    else if (jp == qp->q_head) {
        qp->q_head = jp->j_next;
        if (qp->q_tail == jp)
            qp->q_tail = NULL;
        else
            jp->j_next->j_prev = jp->j_prev;
    } // and this brace was missing in your posted code...
    else if (jp == qp->q_tail) {
        qp->q_tail = jp->j_prev;
        jp->j_prev->j_next = jp->j_next;
    } else {
        jp->j_prev->j_next = jp->j_next;
        jp->j_next->j_prev = jp->j_prev;
    }

    // make sure data in jp no longer refers to
    // the queue - this will also tell any other
    // thread that accesses jp that it's already
    // been removed
    jp->j_next = NULL;
    jp->j_prev = NULL;

    pthread_rwlock_unlock(&qp->q_lock);
}

您還需要檢查jp如何獲得free() d或delete d。 不允許多個線程這樣做。

暫無
暫無

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

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