C线程中pthread_create函数的第4个参数的范围

时间:2018-08-15 09:52:07

标签: c multithreading pthreads

#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

有人可以简要解释一下吗?

3 个答案:

答案 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时,所有线程都从相同位置读取。

问题很少。

  1. 自从main调用pthread_exit以来,一旦主线程退出,您将无法再从其他线程访问i。这是undefined behaviour.

  2. 所有线程实际上(通过i读取myid。这是data race-多个线程访问i而没有任何线程 同步。

请注意,对象的作用域不能确定对象的寿命。它们是相关的但不相同。

答案 2 :(得分:1)

以下建议的代码:

  1. 干净地编译
  2. 执行所需的功能
  3. 更正了OP发布代码中发现的问题
  4. 检查(大多数)错误情况
  5. 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。