C 将参数传递到线程中的安全方法
您能否澄清一下,为什么以下代码是将参数传递到新线程的安全方法:C 将参数传递到线程中的安全方法,c,pthreads,C,Pthreads,您能否澄清一下,为什么以下代码是将参数传递到新线程的安全方法: //Listing 5.3 Passing a Value into a Created Thread for ( int i=0; i<10; i++ ) pthread_create( &thread, 0, &thread_code, (void *)i ); //清单5.3将值传递给创建的线程 对于(int i=0;i第三种方法如下所示: static int args[10]; for (
//Listing 5.3 Passing a Value into a Created Thread
for ( int i=0; i<10; i++ )
pthread_create( &thread, 0, &thread_code, (void *)i );
//清单5.3将值传递给创建的线程
对于(int i=0;i第三种方法如下所示:
static int args[10];
for ( int i=0; i<10; i++ ) {
args[i] = i;
pthread_create( &thread, 0, &thread_code, (void *)&args[i] );
}
static int args[10];
对于(int i=0;i第三种方法如下所示:
static int args[10];
for ( int i=0; i<10; i++ ) {
args[i] = i;
pthread_create( &thread, 0, &thread_code, (void *)&args[i] );
}
static int args[10];
对于(inti=0;iWhy)第二个例子错了吗?
正如你的引文所说,你不能传递一个指向Interaction变量的指针,因为它会很快改变。你永远不知道并发线程何时会使用这个指针并取消引用它
// Listing 5.4 Erroneous Way of Passing Data to a New Thread
for ( int i=0; i<10; i++ )
pthread_create( &thread, 0, &thread_code, (void *)&i );
但是pthread\u create()
只接受void*
(一个通用指针)。该示例使用了一个特殊的技巧,将整数值转换为指针值。线程函数将执行相反的操作(将指针转换回整数)
这种技巧通常用于在需要对象的位置存储整数值,因为它避免了分配和取消分配对象。这种技术是好是坏的做法超出了事实答案的范围。它被用于GLib之类的框架中,但我想许多程序员会对此嗤之以鼻
最后说明
本书中的示例显然不是解决实际问题的方法,而是激励示例。在实际代码中,您很少只传递一个整数值,并且您可能希望在某个时间点加入线程。因此,在一个简单的场景中,您必须分配线程参数,填写它们,启动worker,加入工作检索结果并释放分配
在一个更复杂的场景中,您将与线程通信,因此您将不局限于在创建线程时提供线程,并在加入线程后检索结果。您甚至可以让工作人员在需要时运行并重用线程。为什么第二个示例是错误的?
正如你的引文所说,你不能传递一个指向Interaction变量的指针,因为它会很快改变。你永远不知道并发线程何时会使用这个指针并取消引用它
// Listing 5.4 Erroneous Way of Passing Data to a New Thread
for ( int i=0; i<10; i++ )
pthread_create( &thread, 0, &thread_code, (void *)&i );
但是pthread\u create()
只接受void*
(一个通用指针)。该示例使用了一个特殊的技巧,将整数值转换为指针值。线程函数将执行相反的操作(将指针转换回整数)
这种技巧通常用于在需要对象的位置存储整数值,因为它避免了分配和取消分配对象。这种技术是好是坏的做法超出了事实答案的范围。它被用于GLib之类的框架中,但我想许多程序员会对此嗤之以鼻
最后说明
本书中的示例显然不是解决实际问题的方法,而是激励示例。在实际代码中,您很少只传递一个整数值,并且您可能希望在某个时间点加入线程。因此,在一个简单的场景中,您必须分配线程参数,填写它们,启动worker,加入工作检索结果并释放分配
在一个更复杂的场景中,您将与线程进行通信,因此您不会局限于在创建线程时提供线程,并在加入线程后检索结果。您甚至可以让工作人员在需要时运行并重用线程。显然,您的答案与我在书中读到的答案大不相同。我从逻辑上得出了这个答案。如果我希望每个线程中的不同参数与主线程通信,并且不想执行可能会咬到我的类型转换,那么这符合我的目的。请注意,使用第三种方法,在新线程全部完成之前,您仍然必须确保args
保持在范围内。@immibis是的,您是对的。如果ARGS的寿命可能比线程小,应该考虑制作这些<代码>静态< /代码>,你的答案与我在书中读到的完全不同。我从逻辑上回答了这个问题。如果我希望每个线程中的不同的ARG与主线程通信,并且不想做可能会让我咬错的类型化,那么这就是我的目的。请注意,用这第三种方法,您仍然必须确保<>代码> ARGs<代码>,直到新线程全部完成为止。@ immibIS是的,您是对的。如果ARG的生命可以小于线程,则应该考虑在代码中制作这些<代码>静态< /代码>。“将数据传递给新线程的错误方式"是否保证第一个方法中的i
即使在循环完成后仍保持活动状态?让我们说是的。在启动所有线程后,连接所有线程是合理的。这不是让变量是否活动,而是由“C”规范指导。在您的情况下,它应该是C99或C11。您的书本身说 除非堆栈肯定存在
@MohitJain:在第一种方法中,你根本不依赖变量是否仍然存在。在书中,第二种方法是“将数据传递给新线程的错误方式”是否保证第一个方法中的i
即使在循环完成后仍保持活动状态?让我们说是的。在启动所有线程后,连接所有线程是合理的。这不是让变量是否活动,而是由“C”规范指导。在您的情况下,它应该是C99或C11。您的书本身说 除非堆栈肯定存在
@MohitJain:在第一种方法中,你根本不依赖于变量是否仍然存在。Pavel,谢谢你给出了令人惊讶的答案!我被(void*)
部分欺骗了。现在我似乎很清楚,它只是I
的实际值的容器。然而,(void*)i
不适用于非整数i
,对吗?@Konstantin:Ordinal类型,它基本上就是你可以