当前位置: 首页 > 知识库问答 >
问题:

pthread_create()在EAGAIN 291周期失败

宗政金鹏
2023-03-14

我有以下代码:

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\u num=291的情况下运行此代码时,会出现一个错误:pthread\u create failure,I=291,errno=11(EAGAIN)

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

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

因此,作为尝试,我将我的代码修改为:

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的编程错误。或者我达到了我无法识别的系统极限

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

共有2个答案

司寇烨伟
2023-03-14

我最初写这篇评论,但以防万一。。。

您的代码:

  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\u num进行检查。这意味着您超出了数组线程[thr\u num]的界限,因为数组从索引0开始。因此,您应该从0迭代到小于thr\u num的1:

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

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

赏梓
2023-03-14

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

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

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

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

>

如果线程未分离,则需要对其调用pthread\u join(),以释放资源。

请注意,在循环中调用pthread\u join()的修改代码将:

  1. 生成一个线程
  2. 等待该线程完成
  3. 转到1

也就是说,一次只有另一个线程在运行——这似乎有点毫无意义。

您当然可以生成多个并发运行的线程,但这是有限制的。在您的机器上,您似乎已经发现限制在290左右。

 类似资料:
  • 假设我有一些账单,上面有开始日期和结束日期。 我要检查的商业规则是 例如,3月10日到4月9日大约相隔一个月,所以我用它来检查任何两个连续的账单开始日期(4月10日和3月10日)是否相隔一个月。 现在我的问题是求周期的长度。例如,假设我有以下数据集 我正在使用JodaTime库,所以我说类似这样的话 它返回0,这是正确的,但没有用处。 结果是1,尽管相隔一天。 有什么更好的方法来做到这一点?我可以

  • 注:本文档提供的生命周期指的是 Universal App 的生命周期,它依赖 rax-app 提供的 runApp方法。 App 级生命周期 launch  在 App 启动时触发 使用生命周期 你可以使用 rax-app 提供的 useAppLaunch 来注册 App 级别的生命周期。 示例: import { useAppLaunch } from 'rax-app'; useAppLa

  • 我们大致为WebAPplication设计了4个生命周期: 请求初始化其实就是从URL中解析提取出{module}, {action}, {method}; 然后再根据{module}, {action}, {method}找到对应的Controller文件; 然后再调用对应的{method},完了之后再发送响应。当然响应的过程中肯定是要顺带着解析下模板标签啦。 恩,这就完了,貌似感觉很简单啊。

  • 如下图. 可以看出,基本周期是: created mounted updated (update 可以理解成人肉手动操作触发) destroyed 上面步骤中的 1,3,4都是自动触发。 每个步骤都有对应的 beforeXyz方法 所以, 我们一般使用mounted 作为页面初始化时执行的方法

  • 概览 组件的生命周期分为三个阶段:挂载、渲染、卸载,下图展示了解组件在整个生命周期中所涉及到的方法调用、原型方法调用和状态变化。 挂载阶段 从组件实例被创建再到被插入根组件树中,所经历的操作如下: 初始化组件实例。 根据组件类型绑定对应的原型。 调用 proto->init() 原型方法。 标记组件需要刷新全部样式。 因父组件变为另外一个组件,触发 link 事件。 更新阶段 当组件被插入到根组件

  • 框架生命周期 Hyperf 是运行于 Swoole 之上的,想要理解透彻 Hyperf 的生命周期,那么理解 Swoole 的生命周期也至关重要。 Hyperf 的命令管理默认由 symfony/console 提供支持(如果您希望更换该组件您也可以通过改变 skeleton 的入口文件更换成您希望使用的组件),在执行 php bin/hyperf.php start 后,将由 Hyperf\Se