c - Valgrind/Helgrind 错误地将 TTAS 模式报告为种族

标签 c multithreading pthreads valgrind

我想我发现了 Helgrind 工具返回的相当广泛的误报。也许这已在其他地方记录下来,但 Helgrind 工具似乎总是会错误地检测 Test and Test-And-Set pattern作为误报。

struct resource {
    int in_use;
    int value;
    pthread_mutex_t lock;
}

// assume each member of resource is initialized in the main function
// in_use is initialized to zero
// value is initialized to zero
// and the lock is initialized with pthread_mutex_init() 
struct resource[1000];

void insertIntoUnused(int toInsert) {
    int i;
    for (i = 0; i < 1000; i++) {
        if (resource[i].in_use == 0) {
            pthread_mutex_lock(&resource[i].lock);
            if (resource[i].in_use == 0) {
                resource[i].in_use = 1;
                resource[i].value = toInsert;
                pthread_mutex_unlock(&resource[i].lock);
                return;
            }
            pthread_mutex_unlock(&resource[i].lock);
        }
    }
}

如果许多线程运行上面的 insertIntoUnused 函数,Helgrind 将在第一次读取 in_use 变量时检测到可能的竞争条件。但是,在获取锁后会再次检查 in_use 变量,并且 in_use 变量仅在获取锁时写入

TTAS 模式是一种非常常见的减少锁争用的方法。我很惊讶 Helgrind 无法“支持”这种模式。

我明白为什么 Helgrind 算法在这里检测竞争条件。 in_use 变量的每次读取和每次写入之间不存在 happens-before 关系。然而,证明上面的代码正确并不困难(我实际上还没有把它打出来......所以,除了拼写错误,它在文献中已经很好地确立了)。

如何让 Helgrind 停止考虑首先检查潜在的竞争条件,以便我可以在程序中找到其他竞争条件?

最佳答案

POSIX 线程模型表示,对 resource.in_use 的不同步访问会导致未定义的行为,尽管在本例中它“看起来没问题”。

理论上,编译器可以利用这一点 - 例如,一旦循环的执行将 resource.in_use 视为非零,它就不需要再次测试它,因为(没有数据竞争)在 resource.in_use != 0 情况下没有任何内容可能导致该值发生变化。 IE。它可以将其更改为以下内容:

for (i = 0; i < 1000; i++) {
    if (resource.in_use != 0) {
        i = 1000;
        break;
    }

    pthread_mutex_lock(&resource[i].lock);
    if (resource.in_use == 0) {
        resource.in_use = 1;
        resource.value = toInsert;
        pthread_mutex_unlock(&resource[i].lock);
        return;
    }
    pthread_mutex_unlock(&resource[i].lock);
}

关于c - Valgrind/Helgrind 错误地将 TTAS 模式报告为种族,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28264860/

相关文章:

c++ - 如何将 pthread_t 映射到 pid(在 Linux 上)

区间树的C实现?

java - 如何让Web Service使用多线程?

android - 如何正确使用 AsyncTask

java - 两个线程读取同一张表 :how do i make both thread not to read the same set of data from the TASKS table

c - 在信号处理程序中暂停线程执行

c++ - 继承类为静态

C 读取页面的 HTML

c - 关于字符指针的问题

c - C中管道命令的问题