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

第98次调用pthread\u create()失败

鲁文昌
2023-03-14

我正在运行以下程序。它只会创建直接消亡的线程。

我发现,在93到98次(略有不同)成功调用之后,对pthread\u create()的下一次调用都会失败,错误为11:资源暂时不可用。我认为我正在正确关闭线程,因此它应该放弃它拥有的任何资源,但有些资源变得不可用。

程序的第一个参数允许我设置调用pthread\u create()的间隔,但通过使用不同的值进行测试,我了解到间隔并不重要(好吧,我会在前面得到错误):成功调用的次数将是相同的。

程序的第二个参数允许我在调用失败后设置睡眠间隔,但间隔的长度似乎没有任何区别。

我在这里碰到哪个天花板?

编辑:在doSomething()中发现错误:将lock更改为unlock,程序运行正常。问题仍然是:哪些资源因错误未纠正而耗尽?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#include <errno.h>

pthread_mutex_t doSomethingLock;

void milliSleep(unsigned int milliSeconds)
{
    struct timespec ts;

    ts.tv_sec = floorf(((float)milliSeconds / 1000));
    ts.tv_nsec = ((((float)milliSeconds / 1000) - ts.tv_sec)) * 1000000000;
    nanosleep(&ts, NULL);
}

void *doSomething(void *args)
{
    pthread_detach(pthread_self());
    pthread_mutex_lock(&doSomethingLock);
    pthread_exit(NULL);
}


int main(int argc, char **argv)
{
    pthread_t doSomethingThread;
    pthread_mutexattr_t attr;
    int threadsCreated = 0;


    if (argc != 3)
    {
        fprintf(stderr, "usage: demo <interval between pthread_create() in ms> <time to wait after fail in ms>\n");
        exit(1);
    }

    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
    pthread_mutex_init(&doSomethingLock, &attr);

    while (1)
    {
        pthread_mutex_lock(&doSomethingLock);
        if (pthread_create(&doSomethingThread, NULL, doSomething, NULL) != 0)
        {
            fprintf(stderr, "%d pthread_create(): error %d, %m\n", threadsCreated, errno);
            milliSleep(atoi(argv[2]));
        }
        else threadsCreated++;
        milliSleep(atoi(argv[1]));
    }
}

共有2个答案

段溪叠
2023-03-14

您的程序不会“创建简单消失的线程”。它没有做你认为它做的事情。

首先,pthread_mutex_unlock()只解锁已被同一线程锁定的pthread_mutex_t。互斥锁是这样工作的:它们只能由锁定它们的同一线程解锁。如果您想要信号量信号量的行为,请使用信号量。

您的示例代码创建了一个递归互斥体,函数将尝试锁定该互斥体。因为它由原始线程持有,所以它会阻塞(等待互斥体在调用pthread\u mutex\u lock()时变为空闲)。因为原始线程从未释放锁,所以只需在doSomethingLock互斥锁的顶部堆积新线程。

互斥体的递归性仅仅意味着线程可以多次锁定互斥体;它必须解锁相同次数的互斥锁才能实际释放。

如果您将doThings()中的pthread_mutex_lock()更改为pthread_mutex_unlock(),那么您将尝试解锁该线程未持有的互斥锁。调用失败,然后线程会立即死亡。

假设您修复了程序,接下来会发现创建的线程不能超过100个(取决于您的系统和可用RAM)。

安迪·罗斯很好地解释了原因:固定大小的堆栈(getrlimit(RLIMIT\u STACK,(struct RLIMIT*)

给进程的原始堆栈会自动调整大小,但对于所有其他线程,堆栈大小是固定的。默认情况下,它非常大;在我的系统上,8388608字节(8兆字节)。

我个人创建了具有非常小的堆栈的线程,通常是65536字节,这已经足够了,除非您的函数使用本地数组或大型结构,或者进行疯狂的深度递归:

#ifndef THREAD_STACK_SIZE
#define THREAD_STACK_SIZE  65536
#endif

pthread_attr_t   attrs;
pthread_t        thread[N];
int              i, result;

/* Create a thread attribute for the desired stack size. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE);

/* Create any number of threads.
 * The attributes are only a guide to pthread_create(),
 * they are not "consumed" by the call. */
for (i = 0; i < N; i++) {
    result = pthread_create(&thread[i], &attrs, some_func, (void *)i);
    if (result) {
        /* strerror(result) describes the error */
        break;
    }
}

/* You should destroy the attributes when you know
 * you won't be creating any further threads anymore. */
pthread_attr_destroy(&attrs);

最小堆栈大小应该是PTHREAD_STACK_MIN,并且应该是sysconf(_SC_PAGESIZE)的倍数。目前PTHREAD_STACK_MIN==16384,但我建议使用更大的2的幂。(在任何二进制架构上,页面大小总是2的幂。)

这只是最小值,pthread库可以自由使用它认为合适的任何较大值,但实际上堆栈大小似乎是您设置的值,加上一个固定值,具体取决于体系结构、内核和pthread库版本。使用编译时常量几乎适用于所有情况,但如果您的应用程序足够复杂,因此需要配置文件,那么最好让用户在配置文件中重写编译时常量。

左仰岳
2023-03-14

如果您使用的是32位发行版,您可能会达到地址空间限制。我上次检查时,glibc会在创建的每个线程中为堆栈空间分配大约13MB(这只是映射的大小,而不是分配的内存)。有了98个线程,您将超过3G可用的1 GB地址空间。

您可以通过在出错后冻结进程(例如,睡眠(1000000)或其他什么)并使用pmap查看其地址空间来测试这一点。

如果这是问题所在,请尝试在传递给pthread_createpthread_attr_t上使用pthread_attr_setstack()设置较小的堆栈大小。显然,您必须判断您的堆栈需求,但通常即使是复杂的代码也只能在几KB的堆栈中成功运行。

 类似资料:
  • 考虑下面的代码片段,我试图创建一组线程,这些线程最终处理模拟竞争条件的给定任务。 事情通常工作正常,除了偶尔pthread_create失败与errno EAGAIN"资源暂时不可用",我尝试诱导usap,并重试创建但没有真正的效果。 故障是零星的,在一些盒子上没有故障,在一些盒子上发生得非常频繁。 知道这里会出什么问题吗? 编辑-1 更新最大线程数 编辑2 我认为这里的输入让我思考,我可能会做下

  • 问题内容: 我正在使用 PhoneGap 开发移动应用程序,并且必须 从另一个项目 访问某些 服务 。我正在使用 jquery-2.0.0.js 和 jquery-mobile-1.3.2.js 。 这个ajax调用每次都会失败。在 config.xml中, 我有以下几行: 我可能在哪里错了! 问题答案: 问题在于您的phonegap应用程序正在从非网络服务器请求本地文件。本地文件交付时没有HTT

  • 我刚认识科特林·科鲁廷。我刚刚创建了测试livedata的新项目,但我无法观察到数据的变化。我不明白LiveData的概念。什么时候会触发?因为当我观察ROOM数据库时(不是coroutines方式,我使用的是MutableLiveData),它工作得非常好。Observer总是在数据更改时触发。 我的存储库: 我的ViewModel: 我的主要活动:

  • 98.css 是一个用于构建类似 Windows 98 界面的 CSS 库。 该库依赖于语义 HTML 的用法,例如要编写按钮,需要使用 <button>,输入元素需要标签,图标按钮依赖于 aria-label。支持的组件包括:Button、Checkbox、OptionButton、GroupBox、TextBox、Dropdown、window(Title Bar、Window content

  • 问题内容: 我有一个执行Runtime.getRuntime()。exec(“ ls -l”);的Java程序。很多次,对于系统中的每个目录一次。 我的测试系统有1000多个目录和Runtime.getRuntime()。exec(“ ls -l”); 似乎在480个目录后出错。我收到的错误消息是“运行exec()时出错。命令:[ls,-l]工作目录:空环境:空”。我猜它已经用完了一些必需的系统资

  • 我正在使用webClient调用endpoint并希望将我得到的响应映射到另一个对象。在映射该对象时,我想对响应的某些参数进行额外调用。 我的第一个调用返回以下对象 我把这种反应描绘成这样: 在getCollectionContent方法中,我迭代设置数组,从响应中提取数据并将其映射到PageContent对象。 如果响应包含类型“String”,我只需将数据添加到消息对象中,并将其添加到页面内容