c++ - 另一个线程的调试实例改变了我的数据

标签 c++ c visual-studio-2008 multithreading debugging

我有一个庞大的全局结构数组。数组的某些区域与单独的线程相关联,并且这些线程可以修改它们的数组区域而无需使用临界区。但是数组中有一个特殊区域,所有线程都可以访问。访问数组这些部分的代码需要小心使用临界区(每个数组元素都有自己的临界区),以防止两个线程同时写入结构的任何可能性。

现在我有一个神秘的 bug,我正试图追踪它,它的发生是不可预测的,而且发生的频率非常低。似乎其中一个结构被一些不正确的数字填充。一个明显的解释是另一个线程意外地被允许设置这个数字,而它应该被排除在外。

不幸的是,跟踪这个错误似乎几乎是不可能的。每次出现坏数据的数组元素都不一样。我希望能够做的是为错误设置某种陷阱,如下所示:我将进入数组元素 N 的临界区,然后我知道没有其他线程应该能够触及数据,然后(直到我退出关键部分)为调试工具设置某种标志,说“如果任何其他线程试图更改此处的数据,请中断并向我显示有问题的源代码补丁”......但我怀疑不存在这样的工具。 .. 或者是吗?或者我应该采用一些完全不同的调试方法。

最佳答案

用一个透明的互斥类包装你的数据怎么样?然后您可以应用额外的锁定状态检查。

class critical_section;

template < class T >
class element_wrapper
{
public:
    element_wrapper(const T& v) : val(v) {}
    element_wrapper() {}
    const element_wrapper& operator = (const T& v) {
#ifdef _DEBUG_CONCURRENCY 
        if(!cs->is_locked())
            _CrtDebugBreak();
#endif
        val = v;
        return *this;
    }
    operator T() { return val; }
    critical_section* cs;
private:
    T val;
};

至于关键部分的实现:

class critical_section
{
public:
    critical_section() : locked(FALSE) {
        ::InitializeCriticalSection(&cs);
    }
    ~critical_section() {
        _ASSERT(!locked);
        ::DeleteCriticalSection(&cs);
    }
    void lock() {
        ::EnterCriticalSection(&cs);
        locked = TRUE;
    }
    void unlock() {
        locked = FALSE;
        ::LeaveCriticalSection(&cs);
    }
    BOOL is_locked() {
        return locked;
    }
private:
    CRITICAL_SECTION cs;
    BOOL locked;
};

实际上,除了自定义 critical_section::locked 标志,还可以使用 ::TryEnterCriticalSection(如果成功,后面跟着 ::LeaveCriticalSection ) 以确定是否拥有关键部分。不过,上面的实现几乎一样好。

所以适当的用法是:

typedef std::vector< element_wrapper<int> > cont_t;

void change(cont_t::reference x) { x.lock(); x = 1; x.unlock(); }

int main()
{
    cont_t container(10, 0); 

    std::for_each(container.begin(), container.end(), &change);
}

关于c++ - 另一个线程的调试实例改变了我的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2461924/

相关文章:

c++ - 仅初始化部分功能一次

c - 初始化包含指向数组的指针的结构

visual-studio - Visual Studio 2008 64 位调试策略

c++ - DefWindowProc() 问题

c# - 最好是在接口(interface)上嵌入依赖关系,还是让具体的类来完成这项工作?

c++ - 如何通过a在仅cpp文件的情况下初始化静态成员

c++ - 对 Mat 矩阵执行简单的逆运算和乘法运算

c - 父进程在 Linux shell 上等待上一个子进程

c - GNU Triplet、GCC 和 Linux 内核编译

c++ - 歧义符号