3

我有这个代码:

int main(int argc, char** argv)
{
  pthread_t thread[thr_num];
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

  // just for debugging //
    struct rlimit rlim;
    getrlimit(RLIMIT_NPROC, &rlim);
    printf ("soft = %d \n", rlim.rlim_cur);
    printf ("hard = %d \n", rlim.rlim_max);
  ////

  for ( i = 1 ; i <= thr_num ; i++) {
    if(pthread_create( &thread[i], &attr, loggerThread, (void*)argv ) ) {
      printf("pthread_create failure, i = %d, errno = %d \n", i, errno);
      exit(1);
    }
  }

  pthread_attr_destroy(&attr);

  for ( i = 1 ; i <= thr_num ; i++) {
    if( pthread_join(thread[i], (void**)&status ) ) {
      exit(1);
    }
  }  

  return 0;
}

void* loggerThread(void* data) 
{
  char** sthg = ((char**)data);
  pthread_exit(NULL);
}

我不明白为什么当我使用 thr_num=291 运行此代码时,出现错误:pthread_create failure, i = 291, errno = 11 (EAGAIN)

thr_num=290 工作正常。我在 Linux 2.6.27.54-0.2-default (SLES 11) 上运行此代码 rlim.rlim_cur 的值也为 6906 rlim.rlim_max。我在“最大用户进程”中看到的“ulimit -a”相同。我还检查了 pthread_create 手册页指导的 /proc/sys/kernel/threads-max (它是 13813)。也没有为“sysctl -a”输出找到任何值为 290 的参数。

偶尔我从这个链接中发现: pthread_create and EAGAIN 说:“即使调用了 pthread_exit 或 pthread_cancel,父进程仍然需要调用 pthread_join 来释放 pthread ID,然后它将变为可回收”

所以只是作为一个尝试,我将我的代码修改为:

for ( i = 1 ; i <= thr_num ; i++) {
  if(pthread_create( &thread[i], &attr, loggerThread, (void*)argv ) ) {
    printf("pthread_create failure, i = %d, errno = %d \n", i, errno);
    exit(1);
  }

  if( pthread_join(thread[i], (void**)&status ) ) {
    printf("pthread_join failure, i = %d, errno = %d \n", i, errno);
    exit(1);
  }     
}
pthread_attr_destroy(&attr);

然后一切正常:我在 291 周期没有收到错误。

我想了解为什么我的原始代码会出现错误:1. 因为线程编程错误 2. 或者我遇到了一些我无法识别的系统限制

也想知道我的修正是否对这个问题有好处,或者我最终用这个解决方案引入了哪些隐藏的东西、陷阱?谢谢 !

4

2 回答 2

6

我想了解为什么我的原始代码会出现错误:1. 因为线程编程错误 2. 或者我遇到了一些我无法识别的系统限制

您可能会达到系统限制。很可能你的地址空间用完了。默认情况下,每个线程在 linux 上获得 8-10Mb 的堆栈空间。如果您创建 290 个线程,那将使用近 3Gb 的地址空间——32 位进程的最大值。

在这种情况下,您会得到 EAGAIN,因为现在没有足够的资源来创建线程(因为当时没有足够的可用地址空间)。

当一个线程退出时,并不是线程的所有资源都被释放(在linux上,线程的整个堆栈都被保留了)。

  • 如果线程处于分离状态,例如您调用 pthread_detach() 或在创建它作为 pthread_create() 的属性时指定了分离状态,则在线程退出时释放所有资源 - 但您不能 pthread_join()分离的线程。

  • 如果线程未分离,则需要对其调用 pthread_join() 以释放资源。

请注意,您在循环内调用 pthread_join() 的修改后的代码将:

  1. 产生一个线程
  2. 等待该线程完成
  3. 去 1

即一次只有一个其他线程在运行——这似乎有点毫无意义。

您当然可以生成多个同时运行的线程 - 但有一个限制。在您的机器上,您似乎发现限制在 290 左右。

于 2013-06-12T12:27:02.680 回答
2

我最初将其写为评论,但以防万一...

你的代码:

  for ( i = 1 ; i <= thr_num ; i++) {
    if(pthread_create( &thread[i], &attr, loggerThread, (void*)argv ) ) {
      printf("pthread_create failure, i = %d, errno = %d \n", i, errno);
      exit(1);
    }
  }
...
  for ( i = 1 ; i <= thr_num ; i++) {
    if( pthread_join(thread[i], (void**)&status ) ) {
      exit(1);
    }
  }  

在这两个 for() 循环中,您从 1 到 thr_num 进行检查。这意味着您的数组 thread[thr_num] 超出范围,因为数组从索引 0 开始。因此,您应该从 0 迭代到小于 thr_num 的 1:

for ( i = 0 ; i < thr_num ; i++)

实际上,我很惊讶您在 thr_num 达到 291 之前没有遇到分段错误。

于 2013-06-12T12:54:30.853 回答