如何通过函数的 void 指针参数传递一个 int 值并将其转换回 int 值?

How do you pass an int value through a void pointer paramater of a function and convert it back to an int value?

我正在尝试创建一个多线程程序,为每个接收它的文件创建一个线程(file1.txt 到 file20.txt),我需要将一个变量传递给函数使用 pthread_create。我很难将我的 int 值传递给函数,因为 pthread_create 只接受 void* 所以我的函数必须接受 void*.

我对指针有一些经验,但我不太了解 void 指针的概念。据我所知,我的 pthread_create 应该看起来与 pthread_create(&tids[i], NULL, getSales, (void*)i );

相似

在 main() 中:

using namespace std;

int main(int argc, char **argv){
    int numfiles = 20;
    // Thread_ID's
    pthread_t tids[numfiles];

    // create threads
    for(int i = 1; i <= numfiles; i++){
        pthread_create(&tids[i], NULL, getSales, (void*)i );
    }

    // wait until threads are done
    //join threads together so they run simultaneously
    for(int i = 1; i <= numfiles; i++){
        pthread_join(tids[i], NULL);
    }
}

目前在 getSales 中:

void* getSales(void* fileNum){
    int* num = (int*)fileNum;
    cout << &num <<endl;
    pthread_exit(0);
}

目前,当我编译这段代码时,它崩溃了,并给了我多行回溯,但似乎错误只是 getSales 函数,目前输出应该以随机顺序打印数字 1 到 20,因为该函数是 multi -线程。

gcc staplemax.cpp -lpthread -o staplemax
staplemax.cpp: In function ‘int main(int, char**)’:
staplemax.cpp:114:57: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
         pthread_create(&tids[i], NULL, getSales, (void*)i );
                                                         ^
/tmp/ccf6zgpk.o: In function `getSales(void*)':
staplemax.cpp:(.text+0x10e): undefined reference to `std::cout'
staplemax.cpp:(.text+0x113): undefined reference to `std::ostream::operator<<(void const*)'
staplemax.cpp:(.text+0x118): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'

编辑

我现在使用 g++ staplemax.cpp -lpthread -o staplemax 而不是推荐的 gcc staplemax.cpp -lpthread -o staplemax 进行编译。

我也更改了 main,因为有人指出 &i 可能随着 for 循环的每个循环的调用而更改。我的代码目前看起来像这样

void* getSales(void* fileNum){
    int num = *(int*)fileNum;
    cout << num <<endl;
    pthread_exit(0);
}

int main(int argc, char **argv){
    int numfiles = 20;

    // Thread_ID
    pthread_t tids[numfiles];
    int args[numfiles];

    // create thread
    for(int i = 0; i < numfiles; i++){
        args[i] = i+1;
        pthread_create(&tids[i], NULL, getSales, &args[i] );
    }

   // wait until thread is done  //join
    for(int i = 0; i < numfiles; i++){
        pthread_join(tids[i], NULL);
    }
}

这可以编译(使用 g++)但并非所有数字都是 1-20

3
2
9
1
10
6
87

5
4
11
12
13
14
15
16
17
18
19
20

您将 int 投射到 void*。要撤消它,请将 void* 转换回 int。所以:

int* num = (int*)fileNum;

应该是:

int num = (int)fileNum;

对此的经典解决方案是使用一个对象数组来表示每个 pthread 的参数。也就是说,每个线程都有一个关联的唯一位置来保存它的参数。您只需要传递一个指向该唯一位置的指针。

这是一个例子:

void *pthread_func(void *_arg) {
    int arg = *(int*)_arg; // we're receiving an int
    // ...
}

int main() {
    pthread_t threads[20];
    int       args[20]; // unique arg location for each thread

    for (int i = 0; i < 20; ++i) {
        args[i] = (whatever you want to pass)

        // create the thread, give it its unique arg location
        pthread_create(&threads[i], NULL, pthread_func, &args[i]);
    }

    // ... join the threads, etc. ...
}

通过地址(即 &i)传递循环变量的问题是它可能(肯定会)在每个线程完成之前被更改。

例如,在迭代 i=0 中,您传递了 &i。除非你立即加入 newly-created 线程,否则下一个循环迭代会将 i 更改为 1,这肯定会弄乱你刚刚创建的线程。更糟糕的是,i=0 线程可能永远不会看到 0,因为线程创建可能会延迟,具体取决于系统正在做什么。由于它们都指向相同的位置,因此它们都观察到相同的值(除了迂腐的内存排序考虑因素)。

编辑:

因为您使用的线程数将(应该)总是很小(因为您创建的 运行ning 线程永远不应超过处理器 运行 它们的数量),内存开销上面的方法很小。但是,如果您传递的是整数类型,并且希望尽可能多地保存 space,则可以将其转换为 void*(因为指针也是整数类型)。

唯一需要注意的是,只有当整数类型和指针具有相同的位数时,才允许在它们之间进行转换。为此,请使用 intptr_tuintptr_t 作为中介。

这是一个例子:

void *pthread_func(void *_arg) {
    int arg = (int)(intptr_t)_arg; // we're receiving an int encoded as void*
    // ...
}

int main() {
    pthread_t threads[20];

    for (int i = 0; i < 20; ++i) {
        void *arg = (void*)(intptr_t)(whatever you want to pass);

        // create the thread, give it its packed argument
        pthread_create(&threads[i], NULL, pthread_func, arg);
    }

    // ... join the threads, etc. ...
}