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

时间:2015-02-01 16:20:01

标签: 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无法支持&#34;这种模式。

我理解为什么Helgrind算法在这里检测竞争条件。每次读取happens-before变量与每次写入之间都没有in_use关系。然而,要证明上述代码是正确的并不难(我实际上没有把它输出来......所以,抛开错别字,在文献中已经很好地建立了。)

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

1 个答案:

答案 0 :(得分:1)

POSIX线程模型表示对resource.in_use的非同步访问会导致未定义的行为,无论在这种情况下它“似乎没问题”。

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

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);
}