Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ return function lock_guard

I have the resource "resource" that wrapped in shared_ptr, and I want to access it from other threads. When I do this:

// foo.h
class Foo{
public:
    std::shared_ptr<Setup> GetSomeThing();
    void SetSomeThing();
private:
    std::shared_ptr<Setup> resource;
    std::mutex lock;
}
//Foo.cpp
std::shared_ptr<Setup> Foo::GetSomeThing()
{
    std::lock_guard<std::mutex> lock (mutex);
    return resource;
}

void Foo::SetSomeThing()
{
     std::lock_guard<std::mutex> lock (mutex);
     resource = ...;
}

is it all ok? When will be created a return object and when will be destroyed the lock? Is there something about it in the documentation? Thank you!

like image 494
voltento Avatar asked Oct 17 '25 14:10

voltento


1 Answers

This answer assumes (for clarity) that the two lines:

std::lock_guard<std::mutex> lock (mutex);

are both replaced with

std::lock_guard<std::mutex> guard (lock);

If multiple threads access a single instance of std::shared_ptr<> without synchronization and any of those call non-const members then a data race occurs.

That means you must ensure synchronization between SetSomeThing() and GetSomething().

Introducing a std::mutex and using std::lock_guard<> in the way proposed will do that. The returned copy will have been constructed before the destructor of guard is called.

Do note that it's about the same instance. The copy returned by GetSomeThing() has sufficient internal synchronization to ensure it can be accessed (non-const and even destructed) without synchronizing other instances.

However none of that prevents data races on any shared Setup object (part-)owned by the std::shared_ptr<Setup>. If all access to Setup is read-only then multiple threads can access it but if any threads write to the shared data a data race occurs (without further synchronization not shown in the question).

An object like Setup in a simple application may be constructed and initialized before multiple threads are launched and destructed when all but the main-thread have terminated. In that specific case no further synchronization would be required and even the provided lock is superfluous.

Here's a non-normative reference:

http://en.cppreference.com/w/cpp/memory/shared_ptr

Refer to the last paragraph of the opening description.

Footnote: Changing application "setup" can be far harder than simply ensuring that data races don't occur on the attributes. Threads may need to pend adopting changes or 'abandon' activity. For example consider a graphical program in which the screen resolution is changed during a 'draw' step. Should it finish the draw and produce a canvas that is too large/small or dump the part-drawn canvas and adopt the new resolution? Has the setup even been acquired in such a way that the draw will produce something consistent with 'before' or 'after' and not some nonsensical (possibly crashing) hybrid?

like image 130
Persixty Avatar answered Oct 20 '25 05:10

Persixty