vendredi 31 août 2018

What is the lock state after CondVar.notify_all(); instruction?

I encountered this snippet of code in a book and it looks very strange to me since the convention is to release always the lock but when notify_all() gets called it is not.

My question is whether the lock called from unique_lock gets released automatically after the block gets exited? I know this is released by using RAII lock_guard but that is not my concerned.

class Logger
{
    public:
    // Starts a background thread writing log entries to a file.
    Logger();
    // Prevent copy construction and assignment.
    Logger(const Logger& src) = delete;
    Logger& operator=(const Logger& rhs) = delete;
    // Add log entry to the queue.
    void log(const std::string& entry);

    // Gracefully shut down background thread.
    virtual ~Logger();

    private:
    // The function running in the background thread.

    void processEntries();
    // Mutex and condition variable to protect access to the queue.
    std::mutex mMutex;
    std::condition_variable mCondVar;
    std::queue<std::string> mQueue;
    // The background thread.
    std::thread mThread;

    std::atomic<bool> mExit;
    // Other members omitted for brevity.
};

Logger::Logger()
{
    // Start background thread.
    mThread  = thread{ &Logger::processEntries, this};


}

void Logger::log(const std::string& entry)
{
    // Lock mutex and add entry to the queue.
    unique_lock<mutex> lock(mMutex);
    mQueue.push(entry);
    // Notify condition variable to wake up thread.
    mCondVar.Notify_all();

    // the lock should be released?
}

void Logger::processEntries() 
{
    // Open log file.
    ofstream ofs("log.txt");
    if (ofs.fail()){
        cerr << "Failed to open logfile." << endl;
        return;
    }

    // Start processing loop.
    unique_lock<mutex> lock(mMutex);

    while (true){
        // Wait for a notification.
        mCondVar.wait(lock)
        // Condition variable is notified, so something might be in the queue.
        lock.unlock();

// I am pretty sure the moment lock.unlock() is called the other threads will acquire the lock and the instruction will not jump directly to while(true) which kind of defeats the purpose of the application.
// Code continues...
        while (true){
            lock.lock();
            if (mQueue.empty()) {
                break;
            } else {
                ofs << mQueue.front() << endl;
                mQueue.pop();
            }
            lock.unllock();
        }
    }
}


void logSomeMessages(int id, Logger& logger)
{
    for (int =0; i < 10; ++i){
        stringstream ss;
        ss << "Log entry " << i << " from thread " << id;
        logger.log(ss.str());
    }
}

int main()
{
    Logger logger;
    vector<thread> threads;
    // Create a few threads all working with the same Logger instance.
    for (int i=0; i <10; ++i){
        threads.emplace_back(logSomeMessages, i, ref(logger))
    }

}

Aucun commentaire:

Enregistrer un commentaire