【问题标题】:Avoiding race condition using int to void * casting [duplicate]使用 int 避免竞争条件 void * cast [重复]
【发布时间】:2017-03-19 13:45:56
【问题描述】:

我正在尝试理解以下代码。这段代码没有竞争条件,但我看不懂。

#include <stdio.h>
#include <pthread.h>

void *foo(void *vargp) {
    int id;
    id = (int)vargp;
    printf("Thread %d\n", id);
}

int main() {
    pthread_t tid[2];
    int i;

    for (i = 0; i < 2; i++)
        pthread_create(&tid[i], NULL, foo, (void *)i);
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    return 0;
}

从int 到void* 的类型转换是如何工作的?

【问题讨论】:

  • 强制转换与竞争条件无关,而且似乎这段代码没有说明如何避免竞争条件。
  • “此代码没有竞争条件”。因为它不会在没有同步的情况下访问共享资源,而不是因为任何强制转换。

标签: c pthreads posix


【解决方案1】:

这段代码说明了避免的竞态条件,它与原始代码非常相似,但有细微的不同,并且差异使其不正确:

/* Incorrect code! */
#include <pthread.h>
#include <stdio.h>

static void *foo(void *vargp)
{
    int id = *(int *)vargp;
    printf("Thread %d\n", id);
    return 0;
}

int main(void)
{
    pthread_t tid[2];
    int i;

    for (i = 0; i < 2; i++)
        pthread_create(&tid[i], NULL, foo, &i);  // Bad idea!
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    return 0;
}

由于函数foo 采用void * 参数,因此将int 的地址传递给它似乎是合乎逻辑的。但是,这有一个大问题:

  • 无法保证线程执行的顺序和时间,因此无法知道线程将看到哪些值。

确实,当我第一次运行这段代码时,两个线程都报告了2。

解决这个问题的方法是不传递i 的地址,而是按值传递i。但是,参数仍然应该是void *,因此代码在调用pthread_create() 之前将i 转换为void *,并且线程函数撤消转换以检索值。

当我这样做时,我还使用&lt;stdint.h&gt; 来使uintptr_t 类型可用,并且我使用:

int id = (uintptr_t)vargp;

和

pthread_create(&tid[i], NULL, foo, (void *)(uintptr_t)i);

这看起来过分和/或令人着迷,但uintptr_t 强制转换确保整数与指针大小相同,以避免“cast to pointer from integer of different size”编译器警告(因为我告诉编译器将所有警告视为错误,这对我来说是编译代码所必需的)。

如果您确实将指向数据的指针传递给线程函数(本讨论中为foo),则必须确保您创建的每个线程都获得自己的数据副本,除非该数据在每个线程。

您可以在 POSIX threads — unique execution 中看到这种技术的工作原理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-03
    • 2015-01-30
    • 2010-09-25
    • 2017-12-02
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多