Domanda

I want to write a custom mutex such that each thread can provide an argument that represents the complexity of operations that the current thread wants to execute. If the complexity of the operation is low other threads will be in a loop like a spin lock but if the complexity of the operation is medium each thread will iterate 50 times and then will sleep by condition variable and if operation is very complex other threads will go to sleep directly.

    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();
        };
    };

now assume thread1 locks this mutex and thread2 goes for waiting due to its loopCounter reaching its end and right before locking the condition variable's mutex, thread1 calls notify on the condition variable. Now thread2 will sleep until another thread locks this mutex and then calls unlock on it.

I am new to multithreading and i want to learn. I know that my class may contain errors or may be completely wrong, but is there any way to correct this problem or a good algorithm to write such a mutex.

Another question: Are my atomic operation ordering correctly?

(sorry if my question is somehow ambiguous, my english isn't good)

È stato utile?

Soluzione

I think if i change second if to this:

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; });
}

and unlock to this:

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

problem will solve

Now for optimization can i remove lGuard from unlock method and change std::memory_order_relaxed to std::memory_order_release? (I had doubts to post new question for this or not)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top