Search code examples
c++stdvector

How can I use std::vector safely with mutex?


I use multithreading to read and write a global variable std::deque<int> g_to_be_downloaded_tasks, and I use std::mutex to protect concurrent access. but ThreadB can not get element after ThreadA inserts an element to this vector,

ThreadA

g_to_be_downloaded_tasks_mutex.try_lock();
g_to_be_downloaded_tasks.push_back(temp);
g_to_be_downloaded_tasks_mutex.unlock();

ThreadB: ThreadB gets 0 after using g_to_be_downloaded_tasks.size()

g_to_be_downloaded_tasks_mutex.try_lock();
if(g_to_be_downloaded_tasks.size() > 0)
{
    curr_task = g_to_be_downloaded_tasks.front();
}
g_to_be_downloaded_tasks_mutex.unlock();

Why g_to_be_downloaded_tasks.size() returns 0 ?


Solution

  • You are ignoring the result of try_lock, so you aren't meaningfully using a mutex. Your code has undefined behaviour because of a data race.

    If you never want to block, use the result of try_lock

    if (g_to_be_downloaded_tasks_mutex.try_lock()) {
        g_to_be_downloaded_tasks.push_back(temp);
        g_to_be_downloaded_tasks_mutex.unlock();
    }
    
    if(g_to_be_downloaded_tasks_mutex.try_lock() && (g_to_be_downloaded_tasks.size() > 0))
    {
        curr_task = g_to_be_downloaded_tasks.front();
        g_to_be_downloaded_tasks_mutex.unlock();
    }
    

    More commonly, the producing side would wait for the lock, otherwise it is discarding work

    {
        std::lock_guard guard(g_to_be_downloaded_tasks_mutex);
        g_to_be_downloaded_tasks.push_back(temp);
    }