Guillaume Paris
Guillaume Paris

Reputation: 10539

Lock retains way too long by a thread

I have an application in which several threads share a mutex.

std::lock_guard< std::recursive_mutex > lock(globalMutex_);

One intensively (T1) the others lesser (T2,T3..). I have an example in which the threads which require the lock less often get blocked 100 seconds before successfully acquire the lock.

The tread (T1 so) which acquire the lock often do it in the following way :

void func()
{
  std::lock_guard< std::recursive_mutex > lock(globalMutex_);
  processing();
}

globalMutex_is then well released periodically.

Strange behavior:

T1 get the lock systematically during a total period of 100 seconds while the other thread do not get the lock at all

(In other threads I have the same pattern but the other func is called less often)

Question: What can explain that ? Is it a normal behavior?

Context: I am under windows 10 / last version of Visual Studio / 64 bits / GUI application

Note: Even if I put T2 with a high priority, the situation is the same.

Upvotes: 1

Views: 1561

Answers (3)

Alon
Alon

Reputation: 771

You will achieve your goal with a condition_variable.

std::condition_variable cv;
bool busy = false;
void func()
{
  {
    std::unique_lock<std::mutex> lk(globalMutex_);
    cv.wait(lk, []{return !busy;});
    busy = true;
  }
  processing();
  busy = false;
  cv.notify_one();
}

Upvotes: 0

Solomon Slow
Solomon Slow

Reputation: 27115

This looks like a mistake:

{
  std::lock_guard< std::recursive_mutex > lock(globalMutex_);
  processing();
}

What does processing() do? If it takes more than a few microseconds, then there's probably a more efficient way to solve your problem. Sometimes it looks like this:

bool success=false;
while (! success) {
    auto result = speculative_processing();
    {
        std::lock_guard< std::recursive_mutex > lock(globalMutex_);
        success = attempt_to_publish(result);
    }
}

It's often the case that individual threads in a multi-threaded program have to do extra work in order to keep out of each other's way. But by keeping out of each other's way, they are better able to exploit multiple processors, and they get the whole job done more quickly.

Upvotes: 1

Alan Birtles
Alan Birtles

Reputation: 36379

std::mutex provides no guarantees that mutexes are locked in the order that threads call lock(). When a thread releases the lock if the thread quickly relocks the lock then unless another thread is already waiting on the lock and is executing at the same time the first thread is likely to succeed in regaining the lock.

The simplest solution is to keep locks for as short a time as possible and try to make sure that each thread spends at least some time without the mutex locked.

The more involved solution is to make your own mutex class which does provide some guarantees about the order of lock/unlock. You could implement this with a combination of std::mutex and std::condition_variable.

Upvotes: 2

Related Questions