簡體   English   中英

為什么std :: mutex需要花費很長時間,非常不規律的時間來共享?

[英]Why is std::mutex taking a long, highly irregular amount of time to be shared?

此代碼演示了兩個線程之間共享互斥鎖,但幾乎所有時間都有一個線程。

#include <thread>
#include <mutex>
#include <iostream>

#include <unistd.h>

int main ()
{
    std::mutex m;

    std::thread t ([&] ()
    {
        while (true)
        {
            {
                std::lock_guard <std::mutex> thread_lock (m);

                sleep (1); // or whatever
            }
            std::cerr << "#";
            std::cerr.flush ();
        }
    });

    while (true)
    {
        std::lock_guard <std::mutex> main_lock (m);
        std::cerr << ".";
        std::cerr.flush ();
    }
}

在Ubuntu 18.04 4.15.0-23-generic上用g ++ 7.3.0編譯。

輸出是#和的混合. 字符,顯示共享互斥鎖,但模式令人驚訝。 通常是這樣的:

.......#####..........................##################......................##

thread_lock鎖定互斥鎖長一段時間。 幾秒甚至幾十秒后, main_lock接收控制(簡要地)然后thread_lock將其恢復並保持多年。 調用std::this_thread::yield()不會改變任何東西。

為什么兩個互斥鎖不太可能獲得鎖定,如何以均衡的方式共享互斥鎖?

std::mutex的設計並不公平。 它不能保證鎖定的順序是保持的,你要么幸運得到鎖定。

如果你想要更公平,可以考慮像這樣使用std::condition_variable

#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>

#include <unistd.h>

int main ()
{
    std::mutex m;
    std::condition_variable cv;
    std::thread t ([&] ()
    {
        while (true)
        {
            std::unique_lock<std::mutex> lk(m);
            std::cerr << "#";
            std::cerr.flush ();
            cv.notify_one();
            cv.wait(lk);
        }
    });

    while (true)
    {
        std::unique_lock<std::mutex> lk(m);
        std::cerr << ".";
        std::cerr.flush ();
        cv.notify_one();
        cv.wait(lk);
    }
}

制作std::mutex會產生費用。 在C ++中,你不需要支付你不需要的東西。

你可以編寫一個鎖定對象,釋放鎖的一方不能成為下一個鎖定對象。 更高級,您可以寫一個只有在其他人等待時才會出現這種情況。

這是一個快速的,未經測試的公平互斥的刺:

struct fair_mutex {
  void lock() {
    auto l = internal_lock();
    lock(l);
  }
  void unlock() {
    auto l = internal_lock();
    in_use = false;
    if (waiting != 0) {
      loser=std::this_thread::get_id();
    } else {
      loser = {};
    }
    cv.notify_one();
  }
  bool try_lock() {
    auto l = internal_lock();
    if (in_use) return false;
    lock(l);
    return true;
  }
private:
  void lock(std::unique_lock<std::mutex>&l) {
    ++waiting;
    cv.wait( l, [&]{ return !in_use && std::this_thread::get_id() != loser; } );
    in_use = true;
    --waiting;
  }
  std::unique_lock<std::mutex> internal_lock() const {
    return std::unique_lock<std::mutex>(m);
  }
  mutable std::mutex m;
  std::condition_variable cv;
  std::thread::id loser;
  bool in_use = false;
  std::size_t waiting = 0;
};

它是“公平的”,如果你有兩個線程爭奪資源,他們將輪流。 如果有人在等鎖,任何放棄鎖定的人都不會再抓住它。

但是,這是線程代碼。 所以我可能會讀完它,但我不相信我第一次嘗試寫任何東西。

您可以將此(以不斷增加的成本)擴展為n-way fair(甚至是omega-fair),如果有多達N個元素在等待,它們都會在釋放線程獲得另一個機會之前輪到他們。

暫無
暫無

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

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