dimanche 24 septembre 2017

Does move constructor makes any sense for a class that has std::thread's and std::mutex's as its fields?

Suppose I have a class:

class WonnaBeMovedClass
{
public:

    WonnaBeMovedClass(WonnaBeMovedClass&& other);

    void start();

private:

    void updateSharedData();

    std::vector<int> _sharedData;
    std::thread _threadUpdate;
    std::mutex _mutexShaderData;

    //other stuff
};

WonnaBeMovedClass::WonnaBeMovedClass(WonnaBeMovedClass&& other)
{
    _sharedData = std::move(other._sharedData);
    _threadUpdate = std::move(other._threadUpdate);
    _mutexShaderData = std::move(other._mutexShaderData); //won't compile.
}

void WonnaBeMovedClass::start()
{
    _threadUpdate = std::thread(&updateSharedData, this);
}

void WonnaBeMovedClass::updateSharedData()
{
    std::lock_guard<std::mutex> lockSharedData(_mutexShaderData);

    for (auto& value : _sharedData)
    {
        ++value;
    }
}

It won't compile because mutex cannot be moved. It doesn't make sense. Then I thought that it is possible to workaround this by using pointers instead of actual variables and came up with the following:

class WonnaBeMovedClass
{
public:

    WonnaBeMovedClass(WonnaBeMovedClass&& other);

    void start();

private:

    void updateSharedData();

    std::vector<int> _sharedData;
    std::unique_ptr<std::thread> _threadUpdate //pointer;
    std::unique_ptr<std::mutex> _mutexShaderData //pointer;

    //other stuff
};

WonnaBeMovedClass::WonnaBeMovedClass(WonnaBeMovedClass&& other)
{
    _sharedData = std::move(other._sharedData);
    _threadUpdate = std::move(other._threadUpdate);
    _mutexShaderData = std::move(other._mutexShaderData); //won't compile.
}

void WonnaBeMovedClass::start()
{
    _threadUpdate = std::make_unique<std::thread>(&updateSharedData, this);
}

void WonnaBeMovedClass::updateSharedData()
{
    std::lock_guard<std::mutex> lockSharedData(*_mutexShaderData);

    for (auto& value : _sharedData)
    {
        ++value;
    }
}

So now when I:

WonnaBeMovedClass object1;
WonnaBeMovedClass object2;

//do stuff

object1 = std::move(object2);

I actually move addresses of both mutex and thread. It makes more sense now... Or not?

The thread is still working with the data of object1, not object2, so it still doesn't make any sense. I may have moved the mutex, but the thread is unaware of object2. Or is it? I am unable to find the answer so I am asking you for help.

Am I doing something completely wrong and copying/moving threads and mutexes is just a bad design and I should rethink the architecture of the program?

Aucun commentaire:

Enregistrer un commentaire