【问题标题】:pthread_create() fails with EAGAIN at 291 cyclepthread_create() 在 291 循环时因 EAGAIN 失败
【发布时间】:2013-06-12 09:47:19
【问题描述】:

我有这个代码:

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 失败,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. 或者我遇到了一些我无法识别的系统限制

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

【问题讨论】:

  • 不知道原来的问题是什么,我也很好奇,但是您使用的解决方案使线程使用无用。使用线程的要点是您可以并行执行任务以最大化性能,并且您正在做的是创建一个线程,而不是在创建其他线程之前等待它完成(更多关于 pthread_join:linux.die.net/人/3/pthread_join);功能上最终与调用函数相同,没有额外的好处。 (如果我说错了请有人纠正我)
  • 您在数组中写入超出范围: for ( i = 1 ; i for ( i = 0 ; i
  • 200 多个线程?你一定是在开玩笑吧。打电话给医生!
  • 虽然我同意 200 个线程是多余的,但这可能是一个学术练习。另一方面,可能是在 Parallella、36 核 IBM system z 或能够处理 512 个线程的 16 核 SPARC 上运行的一些代码。

标签: c pthreads


【解决方案1】:

我想了解为什么我的原始代码会出现错误: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 左右。

【讨论】:

  • 内存不足将是 errno 12。正如我在上面的评论中提到的,代码是错误的。在每个 for() 循环中,OP 都超出了范围。我在这里的机器上编译并运行了代码,甚至 32000 +/- 1 个线程都没有问题。
  • @PurpleAlien 你在 64 位机器上。尽管这似乎取决于 glibc 版本,但在此处描述的情况下,您可能会得到 EAGAIN,而不是 ENOMEM。请记住,其他操作系统的行为可能略有不同。
  • 是的,我在 64 位机器上。因此,如果他真的在 32 位机器上运行,那么 OP 会遇到两个问题 - 没有得到澄清。
【解决方案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 小一:

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

我真的很惊讶你在 thr_num 达到 291 之前没有遇到分段错误。

【讨论】:

  • 数组是在栈上分配的,所以我认为thread+thr_num指向的地址没有超出栈空间,从而避免了故障
  • @Rerito,刚刚在这里运行了一些测试,当 thr_num 为奇数时,我得到了段错误。即使 thr_num,也不会发生段错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 2017-01-01
  • 2018-03-30
相关资源
最近更新 更多