在set容器的find()上崩溃

时间:2013-03-20 22:34:49

标签: c++ templates stl crash set

我有一个SyncSet模板类,它锁定了设置操作。当我做压力测试时,我遇到了崩溃。当我检查崩溃输出文件时,似乎原因是关于set container的查找功能。您可以在下面看到我的模板类,您可以在pastebin链接中找到相关的崩溃输出:http://pastebin.com/1JzAWxjf

我的模板类中是否有错误可能导致此类崩溃?其次,操作系统中止应用程序是否可能因为超出内存限制或类似内容,那么有没有办法检查操作系统上的消息(Windows 7专业版)?

所有的意见和评论都很受欢迎。

感谢。

template <typename T>
class SyncSet
{
public:
    SyncSet() {
        InitializeCriticalSection(&m_lock);
    }

    ~SyncSet() {
        DeleteCriticalSection(&m_lock);
    }

    void Insert(T elem) {
        EnterCriticalSection(&m_lock);
        m_set.insert(elem);
        LeaveCriticalSection(&m_lock);
    }

    bool Has(T elem) {
        if (m_set.empty() || m_set.find(elem) == m_set.end())
            return false;

        return true;
    }

    bool Erase(T elem) {
        if (!Has(elem))
            return false;
        EnterCriticalSection(&m_lock);
        m_set.erase(elem);
        LeaveCriticalSection(&m_lock);
        return true;
    }

    size_t Size() {
        return m_set.size();
    }

    void Clear() {
        EnterCriticalSection(&m_lock);
        m_set.clear();
        LeaveCriticalSection(&m_lock);
    }

private:
    std::set<T> m_set;
    CRITICAL_SECTION m_lock;
};

2 个答案:

答案 0 :(得分:2)

您的代码不是线程安全的,因为虽然您保护了对关键部分内的所有写入的写入,但您不保护Has()中的读取。

因此,例如,当另一个线程擦除整个集合时,压力测试可以在Has()调用的中途。

请注意,critical_Section是一个门,只在其他EnterCriticalSection()调用中检查它,并且Has中的find不使用它,因此当另一个线程在临界区内时,那里的代码不会被停止。

答案 1 :(得分:1)

考虑设计一种不同的锁,以增加并行性。

让我们看一下我们目前正在做什么的表格,以及我们允许做什么:

                        Trying to:
                   |  Read  |  Write
           --------|--------|----------
           Nothing |  yes   |  yes
Currently  Reading |  yes   |  no
Doing:     Writing |  no    |  no

任何想要读取的线程都可以这样做,只要没有其他线程在写,并且任何想要写入的线程只有在没有其他线程访问资源的情况下才能这样做。

请注意,如果没有此处未描述的其他工作,此解决方案将具有饥饿条件:尝试写入的线程可能需要等待很长时间才能完成所有读取线程,因为只要任何一个线程都是读取时,写入线程将继续阻塞,但其他读者线程将能够获取其锁定。

对于您正在做的事情,这可能完全有点过分,但如果您希望您的项目能够充分分发,许多线程可能会尝试同时阅读,那么可能值得研究。我知道它没有直接回答你的问题,但是评论太长了,我认为它有可能是有用的。