指针警告(并行计算)
pointer warning (Parallel computing)
我希望我的程序通过将 [a;b] 段拆分为 N 个部分并使用线程计算它来计算函数的定积分。问题是我努力 运行 它正确,我收到以下警告: cast to pointer from integer of different size
我试图通过创建一个指针来解决它,但它随后非常随机地计算(有时它 运行 只是第一个线程或忘记 运行 其中一个)。这是代码的一部分,包括我的尝试:
int main(int argc, char * argv[]) {
pthread_t * threads;
int i;
int *j = &i;
p = (int) strtol (argv[1], 0, 10);
if(!(threads = (pthread_t*) malloc (p*sizeof(pthread_t)))) {
std::cout<<"Not enough memory"<<std::endl;
return -1;
}
for ( i = 0; i < p; ++i) {
if (pthread_create(threads + i, NULL, &run, (void*)j)) { //here comes a trouble
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
for ( i = 0; i < p; ++i) {
if (pthread_join( threads[i], NULL)) {
std::cout << "Waiting error" << std::endl;
return -1;
}
}
free(threads);
pthread_mutex_destroy(&mutex);
std::cout << "Integral f(x) from 0 to 1 = " << S << std::endl;
return 0;
}
我该如何解决?
您第一种方法(将 i
转换为 void *
)中的警告是由 int
和 void *
之间的不同位宽引起的。您的整数很可能是 32 位的,而您的指针是 64 位的(在 64 位构建中很常见)。
它只是告诉你你正在做一些有潜在危险的事情(将变量分配给不同大小的指针),但是由于 pthread_create
等待 void *
(它不用作真正的指针,而只是作为线程启动的传输变量),你不能改变它,它也没有害处(只要你不将它用作真正的指针并且不超过不同位宽的数值限制)
另一方面,您尝试修复警告的指针方法使一切变得更糟。问题是,指针在你的循环中永远不会改变。
j
始终指向 i
,但 i 的内容在循环期间会发生变化。当你的线程启动现在被调用时(已经在它自己的线程上下文中,并且可能已经在一段时间后),它会在你的主线程上下文中获取 i 的 current 内容 - 这可能已经一个甚至更多的循环迭代。这可能是您观察到的 "randomness" 的来源,并且是一个真正的错误。
所以你可以为你的编译器写一个(注释的)ignore pragma 警告,或者你可以为 i 选择一个大小,它匹配指针大小 - 但忽略警告在你的情况下更安全,因为不同版本(32/64 位)的指针大小可能不同
所以确实解决方案是:
for ( i = 0; i < p; ++i) {
// important: just an example. Pragmas and warnings vary per
// compiler, please look in your compiler's reference:
#pragma disable_bit_width_cast_warning
//i instead of j - no pointer, just a copy of i
if (pthread_create(threads + i, NULL, &run, (void*)i)) {
#pragma enable_bit_width_cast_warning
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
另一种解决方案是真正使用指针——但该指针必须是一个副本。在你的线程中使用后你必须删除它:
for ( i = 0; i < p; ++i) {
// hand over a copy of i to your thread startup.
// you'll have to cast the void* back to int* in your thread startup,
// and don't forget to delete it!
if (pthread_create(threads + i, NULL, &run, (void*) new int(i))) {
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
或者您可以 - 就像 NathanOliver 在评论中已经建议的那样 - 使用 std::thread
,这是更好的选择,因为它更安全、更容易、更好用,并且没有这个 void *
问题。 (周围的铸造恕我直言总是有气味)这是一个不错的description and example
我希望我的程序通过将 [a;b] 段拆分为 N 个部分并使用线程计算它来计算函数的定积分。问题是我努力 运行 它正确,我收到以下警告: cast to pointer from integer of different size 我试图通过创建一个指针来解决它,但它随后非常随机地计算(有时它 运行 只是第一个线程或忘记 运行 其中一个)。这是代码的一部分,包括我的尝试:
int main(int argc, char * argv[]) {
pthread_t * threads;
int i;
int *j = &i;
p = (int) strtol (argv[1], 0, 10);
if(!(threads = (pthread_t*) malloc (p*sizeof(pthread_t)))) {
std::cout<<"Not enough memory"<<std::endl;
return -1;
}
for ( i = 0; i < p; ++i) {
if (pthread_create(threads + i, NULL, &run, (void*)j)) { //here comes a trouble
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
for ( i = 0; i < p; ++i) {
if (pthread_join( threads[i], NULL)) {
std::cout << "Waiting error" << std::endl;
return -1;
}
}
free(threads);
pthread_mutex_destroy(&mutex);
std::cout << "Integral f(x) from 0 to 1 = " << S << std::endl;
return 0;
}
我该如何解决?
您第一种方法(将 i
转换为 void *
)中的警告是由 int
和 void *
之间的不同位宽引起的。您的整数很可能是 32 位的,而您的指针是 64 位的(在 64 位构建中很常见)。
它只是告诉你你正在做一些有潜在危险的事情(将变量分配给不同大小的指针),但是由于 pthread_create
等待 void *
(它不用作真正的指针,而只是作为线程启动的传输变量),你不能改变它,它也没有害处(只要你不将它用作真正的指针并且不超过不同位宽的数值限制)
另一方面,您尝试修复警告的指针方法使一切变得更糟。问题是,指针在你的循环中永远不会改变。
j
始终指向 i
,但 i 的内容在循环期间会发生变化。当你的线程启动现在被调用时(已经在它自己的线程上下文中,并且可能已经在一段时间后),它会在你的主线程上下文中获取 i 的 current 内容 - 这可能已经一个甚至更多的循环迭代。这可能是您观察到的 "randomness" 的来源,并且是一个真正的错误。
所以你可以为你的编译器写一个(注释的)ignore pragma 警告,或者你可以为 i 选择一个大小,它匹配指针大小 - 但忽略警告在你的情况下更安全,因为不同版本(32/64 位)的指针大小可能不同
所以确实解决方案是:
for ( i = 0; i < p; ++i) {
// important: just an example. Pragmas and warnings vary per
// compiler, please look in your compiler's reference:
#pragma disable_bit_width_cast_warning
//i instead of j - no pointer, just a copy of i
if (pthread_create(threads + i, NULL, &run, (void*)i)) {
#pragma enable_bit_width_cast_warning
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
另一种解决方案是真正使用指针——但该指针必须是一个副本。在你的线程中使用后你必须删除它:
for ( i = 0; i < p; ++i) {
// hand over a copy of i to your thread startup.
// you'll have to cast the void* back to int* in your thread startup,
// and don't forget to delete it!
if (pthread_create(threads + i, NULL, &run, (void*) new int(i))) {
std::cout << "Cannot create thread" << std::endl;
return -1;
}
}
或者您可以 - 就像 NathanOliver 在评论中已经建议的那样 - 使用 std::thread
,这是更好的选择,因为它更安全、更容易、更好用,并且没有这个 void *
问题。 (周围的铸造恕我直言总是有气味)这是一个不错的description and example