【问题标题】:How to cast an integer to void pointer?如何将整数转换为 void 指针?
【发布时间】:2012-01-19 05:14:06
【问题描述】:

在使用 C 中的线程时,我遇到了警告

“警告:从不同大小的整数转换为指针”

代码如下

#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<pthread.h>
void *print(void *id)
{
 int a=10;
 printf("My thread id is %ld\n",pthread_self());
 printf("Thread %d is executing\n",id);
 return (void *) 42;
}

int main()
{
 pthread_t th[5];
 int t;
 int i;
 int status;
 void *ret;
 for(i=0;i<5;i++)
 {
   status=pthread_create(&th[i],NULL,print,(void *)i); //Getting warning at this line
   if(status)
   {
    printf("Error creating threads\n");
    exit(0);
   }
   pthread_join(th[i],&ret);
   printf("--->%d\n",(int *)ret);
 }
 pthread_exit(NULL);
}

谁能解释如何将整数传递给接收 (void *) 作为参数的函数?

【问题讨论】:

  • 在您的平台上检查sizeof(int)sizeof(void*)。我怀疑它们不同,这就是您看到警告的原因。
  • @Dinesh:请您 1) 向我们展示那些 sizeofs,我从未见过这样的平台,大量 pthread 手册使用您刚刚展示的代码。 2)接受一个不同的答案,你选择的那个是错误的..
  • 请不要接受您选择的答案,因为它是错误的(正如它下面的 cmets 所说)并且会导致错误。
  • 只想指出线程的目的是多任务。例如,在游戏中,您可能有一个线程 t,它获取用户的输入,而主程序则执行其他所有操作。游戏可以在t 等待您按键的同时继续进行。 t 就像一个单独的程序。他们是asynchronous。然而,他们加速你的程序的想法是一种误解。事实上,线程实际上可以减慢你的程序。 CPU 仍然必须一次执行一条指令。不要使用线程来试图获得性能。这是自找麻烦。

标签: c casting void-pointers


【解决方案1】:

如果您需要,这是将整数传递给新 pthread 的好方法。您只需要抑制警告,就可以做到:

#include <stdint.h>

void *threadfunc(void *param)
{
    int id = (intptr_t) param;
    ...
}

int i, r;
r = pthread_create(&thread, NULL, threadfunc, (void *) (intptr_t) i);

讨论

这可能会冒犯您的感受,但它非常短并且没有竞争条件(就像您使用 &amp;i 时一样)。仅仅为了获得一堆编号的线程而编写几十行额外的代码是没有意义的。

数据竞赛

这是一个带有数据竞争的糟糕版本:

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

#define N 10

void *thread_func(void *arg)
{
    int *ptr = arg;
    // Has *ptr changed by the time we get here?  Maybe!
    printf("Arg = %d\n", *ptr);
    return NULL;
}

int main()
{
    int i;
    pthread_t threads[N];
    for (i = 0; i < N; i++) {
        // NO NO NO NO this is bad!
        pthread_create(&threads[i], NULL, thread_func, &i);
    }
    for (i = 0; i < N; i++) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}

现在,当我使用线程清理程序运行它时会发生什么?

(另外,看看它是如何打印“5”两次的......)

=================== 警告:ThreadSanitizer:数据竞争(pid=20494) 线程 T1 在 0x7ffc95a834ec 读取大小 4: #0 thread_func /home/depp/test.c:9 (a.out+0x000000000a8c) #1 (libtsan.so.0+0x000000023519) 先前由主线程在 0x7ffc95a834ec 写入大小 4: #0 主 /home/depp/test.c:17 (a.out+0x000000000b3a) 位置是主线程的堆栈。 主线程在以下位置创建的线程 T1 (tid=20496, running): #0 pthread_create (libtsan.so.0+0x0000000273d4) #1 主 /home/depp/test.c:18 (a.out+0x000000000b1c) 摘要:ThreadSanitizer:数据竞争 /home/depp/test.c:9 thread_func =================== 精氨酸 = 1 精氨酸 = 2 精氨酸 = 3 精氨酸 = 4 精氨酸 = 5 精氨酸 = 6 精氨酸 = 7 精氨酸 = 8 精氨酸 = 9 精氨酸 = 5 ThreadSanitizer:报告 1 个警告

【讨论】:

  • +1 绝对正确,但是如果您花时间编写 struct {},将来当您想要接收/发送更多数据而不是 int 时,您可以省去很多麻烦跨度>
  • @jackdoe:编写“你将来可能需要”的代码是在浪费生命。
  • @DietrichEpp 你能解释一下在pthread_create() 中使用(void *)&amp;i 是什么竞争条件吗,我正在使用它并且编译器没有显示警告,我在想但无法弄清楚,我我也像这样int *b=(int*)a将传递给线程的值转换为this
  • @Xax:首先(void *)是多余的,用&amp;i就行了。此外,编译器不会警告您竞争条件,您必须自己弄清楚(或使用特殊工具)。出现竞争条件是因为您必须等到每个线程完成读取 i 之后才能更改 i 或让它离开范围。以下是可能出错的示例:gist.github.com/depp/241d6f839b799042c409
  • @Xax:这是一个固定版本,没有竞争条件:gist.github.com/depp/3f04508a88a114734195
【解决方案2】:

你可以这样做:

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <pthread.h>
struct th {
    pthread_t thread;
    int id;
    int ret;
};

void *print(void *id) {
    int a=10;
    struct th *self = (struct th *) id;
    printf("My thread id is %ld\n",pthread_self());
    printf("Thread %d is executing\n",self->id);
    self->ret = random();
    return;
}

int main(void) {
    struct th th[5];
    int t;
    int i;
    int status;
    void *ret;
    for(i=0;i<5;i++) {
        th[i].id = i;
        status=pthread_create(&th[i].thread,NULL,print,&th[i]); //Getting warning at this line
        if(status) {
            printf("Error creating threads\n");
            exit(0);
        }
    }
    for (i=0;i<5;i++) {
        pthread_join(th[i].thread,&ret);
        printf("%d--->%d\n",th[i].id,th[i].ret);

    }
    pthread_exit(NULL);
}

将输出:

My thread id is 4496162816
My thread id is 4497870848
My thread id is 4498944000
My thread id is 4498407424
Thread 0 is executing
Thread 1 is executing
My thread id is 4499480576
Thread 3 is executing
Thread 2 is executing
0--->1804289383
Thread 4 is executing
1--->846930886
2--->1714636915
3--->1681692777
4--->1957747793

向每个线程传递一个唯一的指针不会竞争,您可以在第一个结构中获取/保存任何类型的信息

【讨论】:

    【解决方案3】:

    您可以将 int 值作为 void 指针传递,例如 (void *)&amp;n,其中 n 是整数,并在函数中接受 void 指针作为参数,例如 void foo(void *n);,最后在函数内部将 void 指针转换为 int,例如 int num = *(int *)n;。这样你就不会收到任何警告。

    【讨论】:

      【解决方案4】:

      改变:

      status=pthread_create(&th[i],NULL,print,(void *)i);
      

      到:

      status=pthread_create(&th[i],NULL,print,(reinterpret_cast<void*>(i));
      

      reinterpret_cast 使 int 成为指针的大小,警告将停止。基本上它是 (void *)i 的更好版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-19
        • 2018-12-10
        • 1970-01-01
        • 2016-01-12
        • 2012-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多