2013-10-03 67 views
2

我想寫一個自定義互斥鎖,以便每個線程都可以提供一個參數,該參數表示當前線程想要執行的操作的複雜性。如果操作的複雜度較低,其他線程將像循環鎖一樣循環,但如果操作的複雜度爲中,每個線程將迭代50次,然後將通過條件變量休眠,如果操作非常複雜,其他線程將直接睡覺。將線程置於自旋鎖的睡眠方式

enum LockOperation 
    { 
     LockOperation_Light = -1, 
     LockOperation_Medium = 50, 
     LockOperation_Heavy = 1 
    }; 

    class CustomMutex 
    { 
    private: 

    protected: 
     std::atomic<int> mFlag; 
     std::mutex mMutex; 
     std::condition_variable mCond; 

    public: 
     CustomMutex() { std::atomic_init(&mFlag, 0); }; 
     ~CustomMutex() {}; 

     void lock(LockOperation pLockOperation = LockOperation_Medium) 
     { 
      int lNewLoopCount = static_cast<int>(pLockOperation); 
      int lLoopCounter = 0; 
      int lExpected = 0; 
      int lLoopCount = std::atomic_load_explicit(&mFlag, std::memory_order_relaxed); 

      while (true) 
      { 
       while(std::atomic_load_explicit(&mFlag, std::memory_order_relaxed) != 0 && 
         lLoopCounter != lLoopCount) 
        ++lLoopCounter; 
       std::atomic_compare_exchange_strong_explicit(
        &mFlag, 
        &lExpected, 
        lNewLoopCount, 
        std::memory_order_acquire, 
        std::memory_order_relaxed); 
       if(lExpected == 0) 
       { 
        return; 
       } 
       else if(lLoopCounter == lLoopCount) 
       { 
        lExpected = 0; 
        std::unique_lock<std::mutex> lGuard(mMutex); 
        mCond.wait(lGuard); 
       } 
       else 
       { 
        lExpected = 0; 
        continue; 
       } 
      } 
     }; 
     bcInline void UnLock() 
     { 
      std::atomic_store_explicit(&mFlag, 0, std::memory_order_relaxed); 
      std::lock_guard<std::mutex> lGuard(mMutex); 
      mCond.notify_one(); 
     }; 
    }; 

現在假設線程1鎖定這個互斥及線程無二由於等待其循環計數器達到其最終和右鎖定條件變量的互斥體之前,線程1調用條件變量通知。現在thread2會睡覺,直到另一個線程鎖定此互斥鎖,然後調用解鎖。

我是新來的多線程,我想學習。我知道我的類可能包含錯誤或者可能是完全錯誤的,但是有什麼方法可以糾正這個問題或者寫一個這樣的互斥體的好算法。

另一個問題:我的原子操作是否正確排序?

(對不起,如果我的問題是有點含糊,我的英語不是很好)

+0

旋轉鎖在用戶空間中是一個壞主意。在大多數設計良好的應用程序中,互斥量爭用非常罕見 - 並且「無爭議」鎖的代碼路徑通常會進行高度優化。作爲'light','medium'或'heavy'的操作分類是使我想到[優先倒置](http://en.wikipedia.org/wiki/Priority_inversion)問題的事情之一。 –

+0

我必須同意@BrettHale :( –

+0

@BrettHale好吧,但我認爲在我的示例中不會出現優先級反轉問題。light,medium和heavy只是互斥量的所有者告訴等待線程必須循環多少的標誌我認爲在輕量級和重度級操作之間沒有優先權爭奪,並且獲取互斥體仍然是隨機的。爲什麼你說自旋鎖是一個壞主意?在'輕量級操作'中就像添加或移除鏈表這會是一個好主意,我們讓線程自動調用,而不是調用互斥鎖(我不明白'旋轉鎖在用戶空間中是一個壞主意')。 – MRB

回答

0

我想,如果我改變第二,如果這樣:

else if(lLoopCounter == lLoopCount) 
{ 
    lExpected = 0; 
    std::unique_lock<std::mutex> lGuard(mMutex); 
    mCond.wait(
     lGuard, 
     [&]()->bool { return std::atomic_load_explicit(&mFlag, std::memory_order_relaxed) == 0; }); 
} 

和解鎖這樣:

std::lock_guard<std::mutex> lGuard(mMutex); 
std::atomic_store_explicit(&mFlag, 0, std::memory_order_relaxed); 
mCond.notify_one(); 

問題將會解決

現在對於優化可以i。從解鎖方法的除去lGuard nd將std :: memory_order_relaxed更改爲std :: memory_order_release? (我曾懷疑是否會爲此發佈新問題)