簡體   English   中英

優先隊列與 pthreads 同步

[英]Priority Queue synchronization with pthreads

我正在完成一項大學作業,我們將在其中實施並行 A* 搜索15 謎題 對於這一部分,我們將只使用一個優先級隊列(我想看到多個線程的爭用會限制加速)。 我面臨的一個問題是正確同步從優先級隊列中彈出下一個“候選人”。

我嘗試了以下方法:

while(1) {
  // The board I'm trying to pop.
  Board current_board;

  pthread_mutex_lock(&priority_queue_lock);
  // If the heap is empty, wait till another thread adds new candidates.
  if (pq->heap_size == 0)
  {
    printf("Waiting...\n");
    pthread_mutex_unlock(&priority_queue_lock);
    continue;
  }
  current_board = top(pq);
  pthread_mutex_unlock(&priority_queue_lock);

  // Generate the new boards from the current one and add to the heap...
}

我嘗試過相同想法的不同變體,但由於某種原因,有時線程會卡在“等待”中。 該代碼可以串行(或使用兩個線程)正常工作,因此讓我相信這是代碼的違規部分。 如有必要,我可以發布整個內容。 不過,我覺得這是我對互斥鎖的理解的問題。 提前感謝您的幫助。

編輯:我在下面添加了並行線程的完整代碼:

// h and p are global pointers initialized in main()
void* parallelThread(void* arg)
{
    int thread_id = (int)(long long)(arg);
    while(1)
    {
        Board current_board;

        pthread_mutex_lock(&priority_queue_lock);
        current_board = top(p);
        pthread_mutex_unlock(&priority_queue_lock);

        // Move blank up.
        if (current_board.blank_x > 0)
        {
            int newpos = current_board.blank_x - 1;
            Board new_board = current_board;
            new_board.board[current_board.blank_x][current_board.blank_y] = new_board.board[newpos][current_board.blank_y];
            new_board.board[newpos][current_board.blank_y] = BLANK;
            new_board.blank_x = newpos;

            new_board.goodness = get_goodness(new_board.board);
            new_board.turncount++;

            if (check_solved(new_board))
            {
                printf("Solved in %d turns",new_board.turncount);
                exit(0);
            }

            if (!exists(h,new_board))
            {
                insert(h,new_board);
                push(p,new_board);
            }
        }

        // Move blank down.
        if (current_board.blank_x < 3)
        {
            int newpos = current_board.blank_x + 1;
            Board new_board = current_board;
            new_board.board[current_board.blank_x][current_board.blank_y] = new_board.board[newpos][current_board.blank_y];
            new_board.board[newpos][current_board.blank_y] = BLANK;
            new_board.blank_x = newpos;

            new_board.goodness = get_goodness(new_board.board);
            new_board.turncount++;

            if (check_solved(new_board))
            {
                printf("Solved in %d turns",new_board.turncount);
                exit(0);
            }

            if (!exists(h,new_board))
            {
                insert(h,new_board);
                push(p,new_board);
            }
        }

        // Move blank right.
        if (current_board.blank_y < 3)
        {
            int newpos = current_board.blank_y + 1;
            Board new_board = current_board;
            new_board.board[current_board.blank_x][current_board.blank_y] = new_board.board[current_board.blank_x][newpos];
            new_board.board[current_board.blank_x][newpos] = BLANK;
            new_board.blank_y = newpos;

            new_board.goodness = get_goodness(new_board.board);
            new_board.turncount++;

            if (check_solved(new_board))
            {
                printf("Solved in %d turns",new_board.turncount);
                exit(0);
            }

            if (!exists(h,new_board))
            {
                insert(h,new_board);
                push(p,new_board);
            }
        }

        // Move blank left.
        if (current_board.blank_y > 0)
        {
            int newpos = current_board.blank_y - 1;
            Board new_board = current_board;
            new_board.board[current_board.blank_x][current_board.blank_y] = new_board.board[current_board.blank_x][newpos];
            new_board.board[current_board.blank_x][newpos] = BLANK;
            new_board.blank_y = newpos;

            new_board.goodness = get_goodness(new_board.board);
            new_board.turncount++;

            if (check_solved(new_board))
            {
                printf("Solved in %d turns",new_board.turncount);
                exit(0);
            }

            if (!exists(h,new_board))
            {
                insert(h,new_board);
                push(p,new_board);
            }
        }
    }

    return NULL;
}

我嘗試了以下方法:

我看不出后面的代碼有什么問題,假設top也從隊列中刪除了板。 這很浪費(如果隊列為空,它將旋轉鎖定和解鎖互斥鎖),但沒有錯。

我已經添加了完整的代碼

如果沒有existsinsertpush的代碼,這是沒有用的。

一項一般性觀察:

    pthread_mutex_lock(&priority_queue_lock);
    current_board = top(p);
    pthread_mutex_unlock(&priority_queue_lock);

在上面的代碼中,您的鎖定是top function 的“外部”。 但在這兒:

        if (!exists(h,new_board))
        {
            insert(h,new_board);
            push(p,new_board);
        }

你要么根本不鎖定(在這種情況下這是一個錯誤),要么你鎖定“內部” existsinsertpush

您不應該混合“內部”和“外部”鎖定。 選擇其中一個並堅持下去。

如果您實際上沒有將隊列鎖定在existsinsert等內部,那么您有數據競爭並且錯誤地考慮了互斥鎖:它們保護不變量,並且您無法檢查隊列是否與另一個線程並行執行“刪除頂部元素”——這些操作需要序列化,因此都必須在鎖定下完成。

暫無
暫無

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

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