为什么在没有可变声明的情况下此代码失败?

时间:2018-08-13 02:01:39

标签: c linux multithreading

我下面的代码来自一本书,该书是在Ubuntu 18.4上使用Eclipse -O0 -g3编译的

#include <pthread.h>
#include <stdio.h>

void *myThread( void *arg )
{
  printf( "Thread %d started\n", (int)arg );

  pthread_exit( arg );
}

#define MAX_THREADS 5

int main()
{
  volatile int  i;
  int status;
  int ret;
  pthread_t threadIds[MAX_THREADS];

  for (i = 0 ; i < MAX_THREADS ; i++) {
    ret = pthread_create( &threadIds[i], NULL, myThread, (void *)i );
    if (ret != 0) {
      printf( "Error creating thread %d\n", (int)threadIds[i] );
    }
  }

  for (i = 0 ; i < MAX_THREADS ; i++) {
    printf("-----------  i = %d\n",i);
    ret = pthread_join( threadIds[i], (void **)&status );
    if (ret != 0) {
      printf( "Error joining thread %d\n", (int)threadIds[i] );
    } else {
      printf( "Status = %d\n", status );
    }
  }

  return 0;
}

此代码可以正常工作并产生输出

-----------  i = 0
Thread 3 started
Thread 0 started
Status = 0
-----------  i = 1
Thread 2 started
Thread 1 started
Status = 1
-----------  i = 2
Status = 2
-----------  i = 3
Status = 3
-----------  i = 4
Thread 4 started
Status = 4

但是,如果忽略变量i声明中的 volatile 关键字,则会产生以下输出:

Thread 1 started
Thread 0 started
Thread 2 started
Thread 3 started
-----------  i = 0
Status = 0
-----------  i = 1
Status = 1
-----------  i = 1
Error joining thread -947054848
-----------  i = 2
Status = 2
-----------  i = 1
Error joining thread -947054848
-----------  i = 2
Error joining thread -955447552
-----------  i = 3
Status = 3
-----------  i = 1
Error joining thread -947054848
-----------  i = 2
Error joining thread -955447552
-----------  i = 3
Error joining thread -963840256
-----------  i = 4
Thread 4 started
Status = 4
-----------  i = 1
Error joining thread -947054848
-----------  i = 2
Error joining thread -955447552
-----------  i = 3
Error joining thread -963840256
-----------  i = 4
Error joining thread -1073744128

请帮助我确定可能导致此问题的问题。

1 个答案:

答案 0 :(得分:4)

在您的代码中:

int status;

// ...

pthread_join( threadIds[i], (void **)&status );

这是严格的别名冲突。 pthread_join向位置写入类型void *的值,但是您提供了int的位置。这会导致不确定的行为,意味着任何事情都可能发生。

您的系统上可能发生的情况是写越界(int = 4字节,void * = 8字节),使堆栈混乱,导致混乱。

您可以使用以下方法解决此问题:

void *status;
// ...
pthread_join( threadIds[i], &status );

以后,如果要使用%d打印状态,请使用(int)status作为参数。