#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// Let us create a global variable to change it in threads
int g = 0;
// The function to be executed by all threads
void *myThreadFun(void *vargp)
{
// Store the value argument passed to this thread
int *myid = (int *)vargp;
// Let us create a static variable to observe its changes
static int s = 0;
// Change static and global variables
++s; ++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", *myid, ++s, ++g);
}
int main()
{
int i;
pthread_t tid;
// Let us create three threads
for (i = 0; i < 3; i++)
pthread_create(&tid, NULL, myThreadFun, (void *)&i);
pthread_exit(NULL);
return 0;
}
我只是在使用C中的多线程处理上述示例,并且我对2个线程使用了相同的线程ID,这不应该是因为myid
是本地指针,并且每个指针应该打印不同。 / p>
我得到的输出如下:
Thread ID: 3, Static: 2, Global: 2
Thread ID: 3, Static: 4, Global: 4
Thread ID: 3, Static: 6, Global: 6
有人可以简要解释一下吗?
答案 0 :(得分:3)
您将非常相同的指针传递给所有三个线程。所有线程都将取消引用相同的指针,从而获得相同的值。
然后,因为调用了pthread_exit
,指针指向的数据将不再有效。这意味着取消引用将导致undefined behavior。
此外,因为您在不同步的情况下访问和修改共享数据,因此数据争用再次导致未定义行为。
通过传递i
的 value 而不是指针可以很容易地解决前两个问题。这是大多数人认为可以假装整数是指针的少数情况之一。您必须进行一些强制转换才能使其正常工作:
pthread_create(&tid, NULL, myThreadFun, (void *) (intptr_t) i);
然后,在获取值时必须进行相反的转换:
int myid = (int) (intptr_t) vargp;
答案 1 :(得分:1)
我有2个线程相同的线程ID,这不应该是因为myid是一个本地指针,并且每个线程都应该打印不同的内容。
myid
是一个本地指针,但实际上是指向另一个线程的地址。您创建的所有3个线程中的myid
指向main中i
的相同地址。因此,当取消引用myid
时,所有线程都从相同位置读取。
问题很少。
自从main
调用pthread_exit
以来,一旦主线程退出,您将无法再从其他线程访问i
。这是undefined behaviour.
所有线程实际上(通过i
读取myid
。这是data race-多个线程访问i
而没有任何线程
同步。
请注意,对象的作用域不能确定对象的寿命。它们是相关的但不相同。
答案 2 :(得分:1)
以下建议的代码:
main()
函数使用正确的签名现在是建议的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 3
// Let us create a global variable to change it in threads
int g = 0;
pthread_mutex_t myMutex;
// The function to be executed by all threads
void *myThreadFun( void *vargp )
{
// Store the value argument passed to this thread
int myid = (int) (intptr_t) vargp;
// Let us create a static variable to observe its changes
static int s = 0;
pthread_mutex_lock( &myMutex );
// Change static and global variables
++s;
++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
pthread_mutex_unlock( &myMutex );
pthread_exit( NULL );
}
int main( void )
{
pthread_t tid[ NUM_THREADS ] = {0};
if (pthread_mutex_init(&myMutex, NULL) != 0)
{
perror( "pthread_mutex_init failed" );
exit( EXIT_FAILURE );
}
// implied else, init successful
// Let us create three threads
for ( int i = 0; i < NUM_THREADS; i++)
{
if(pthread_create(&tid[i], NULL, myThreadFun, (void *) (intptr_t) i) != 0 )
{
perror( "pthread_create failed" );
exit( EXIT_FAILURE );
}
}
// collect the threads
for( int i=0; i< NUM_THREADS; i++ )
{
if( pthread_join( tid[i], NULL ) != 0 )
{
perror( "pthread_join failed" );
}
}
pthread_mutex_destroy( &myMutex );
return 0;
}
该程序的典型运行会产生以下输出:
Thread ID: 0, Static: 1, Global: 1
Thread ID: 2, Static: 2, Global: 2
Thread ID: 1, Static: 3, Global: 3
注意:声称是线程ID的字段仅是创建线程的顺序,而不是实际的线程ID。