我有一个对象列表,每个对象都有成员变量,这些成员变量是通过“更新”函数计算的。我想并行更新对象,也就是我想为每个对象创建一个线程以执行其更新功能。

这是合理的做法吗?有什么原因可能不是个好主意?

下面是一个尝试执行我所描述的程序,这是一个完整的程序,因此您应该可以运行它(我使用的是VS2015)。目标是并行更新每个对象。问题在于,一旦更新功能完成,线程将引发“将发生资源死锁”异常并中止。

我要去哪里错了?

#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
#include <chrono>

class Object
{
public:

    Object(int sleepTime, unsigned int id)
        : m_pSleepTime(sleepTime), m_pId(id), m_pValue(0) {}

    void update()
    {
        if (!isLocked()) // if an object is not locked
        {
            // create a thread to perform it's update
            m_pThread.reset(new std::thread(&Object::_update, this));
        }
    }

    unsigned int getId()
    {
        return m_pId;
    }

    unsigned int getValue()
    {
        return m_pValue;
    }

    bool isLocked()
    {
        bool mutexStatus = m_pMutex.try_lock();

        if (mutexStatus) // if mutex is locked successfully (meaning it was unlocked)
        {
            m_pMutex.unlock();
            return false;
        }
        else // if mutex is locked
        {
            return true;
        }
    }

private:

    // private update function which actually does work
    void _update()
    {
        m_pMutex.lock();
        {
            std::cout << "thread " << m_pId << " sleeping for " << m_pSleepTime << std::endl;
            std::chrono::milliseconds duration(m_pSleepTime);
            std::this_thread::sleep_for(duration);

            m_pValue = m_pId * 10;
        }
        m_pMutex.unlock();

        try
        {
            m_pThread->join();
        }
        catch (const std::exception& e)
        {
            std::cout << e.what() << std::endl; // throws "resource dead lock would occur"
        }
    }

    unsigned int m_pSleepTime;
    unsigned int m_pId;
    unsigned int m_pValue;
    std::mutex m_pMutex;
    std::shared_ptr<std::thread> m_pThread; // store reference to thread so it doesn't go out of scope when update() returns
};

typedef std::shared_ptr<Object> ObjectPtr;

class ObjectManager
{
public:
    ObjectManager()
        : m_pNumObjects(0){}

    void updateObjects()
    {
        for (int i = 0; i < m_pNumObjects; ++i)
        {
            m_pObjects[i]->update();
        }
    }

    void removeObjectByIndex(int index)
    {
        m_pObjects.erase(m_pObjects.begin() + index);
    }

    void addObject(ObjectPtr objPtr)
    {
        m_pObjects.push_back(objPtr);
        m_pNumObjects++;
    }

    ObjectPtr getObjectByIndex(unsigned int index)
    {
        return m_pObjects[index];
    }

private:
    std::vector<ObjectPtr> m_pObjects;
    int m_pNumObjects;
};

void main()
{
    int numObjects = 2;

    // Generate sleep time for each object
    std::vector<int> objectSleepTimes;
    objectSleepTimes.reserve(numObjects);

    for (int i = 0; i < numObjects; ++i)
        objectSleepTimes.push_back(rand());

    ObjectManager mgr;

    // Create some objects
    for (int i = 0; i < numObjects; ++i)
        mgr.addObject(std::make_shared<Object>(objectSleepTimes[i], i));

    // Print expected object completion order
    // Sort from smallest to largest
    std::sort(objectSleepTimes.begin(), objectSleepTimes.end());

    for (int i = 0; i < numObjects; ++i)
        std::cout << objectSleepTimes[i] << ", ";
    std::cout << std::endl;

    // Update objects
    mgr.updateObjects();

    int numCompleted = 0;  // number of objects which finished updating
    while (numCompleted != numObjects)
    {
        for (int i = 0; i < numObjects; ++i)
        {
            auto objectRef = mgr.getObjectByIndex(i);

            if (!objectRef->isLocked()) // if object is not locked, it is finished updating
            {
                std::cout << "Object " << objectRef->getId() << " completed. Value = " << objectRef->getValue() << std::endl;
                mgr.removeObjectByIndex(i);
                numCompleted++;
            }
        }
    }

    system("pause");
}

最佳答案

看来您有一个试图加入自身的线程。

08-20 02:44