首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何解决pthread_create错误(11)资源暂时不可用?

如何解决pthread_create错误(11)资源暂时不可用?
EN

Stack Overflow用户
提问于 2020-06-16 13:19:21
回答 1查看 9.6K关注 0票数 0

我正在用c语言构建一个项目(使用openwrt作为操作系统)将文件上传到FTP服务器。我用MQTT来处理输入的数据。因此,对于我订阅的每个主题,我保存这些数据,然后将其上传到FTP服务器,为了保持工作顺利进行,每次我需要上传一个文件时,我只是使用一个线程来完成这个工作。为了确保程序不会运行太多线程,每个主题都可以创建一个线程。我使用一个变量(比如互斥变量,但它不是pthread_mutex_t,因为我不需要阻止线程,我想跳过这个步骤并上传下一个文件)。我认为使用这种技术我是安全的,但是在运行程序15分钟之后,我得到了这个错误11,它表示当程序试图创建一个线程(pthread_create)时,资源暂时不可用。我想找出问题出在哪里。

  • 我使用了pthread_join()函数,它在我的条件下不是一个选项,只是为了确保每个线程都完成了,而不是在永久循环中运行。程序运行了一个多小时,错误没有再次出现。当然,每个线程都是按预期完成的。
  • 和我90%肯定每个主题只在线程上创建,下一个主题只有在前一个主题完成后才会创建。(在创建线程之前和之后,我一直在跟踪变量的状态)
  • 从这里开始将最大线程设置为“/proc/sys/内核/ max”到2000 (2000年就足够了,因为我没有太多的主题)

上传函数(这将创建线程):

代码语言:javascript
运行
复制
void uploadFile(<args...>, bool* locker_p){
    *locker_p = true;
    args->uploadLocker_p = uploadLocker_p;

    <do something here>

    pthread_t tid;
    int error = pthread_create(&tid, NULL, uploadFileThread, (void*)args);
        if(0 != error){
            printf("Couldn't run thread,(%d) => %s\n", error, strerror(error));
    }
        else{
            printf("Thread %d\n", tid);
    }
}

上传线程:

代码语言:javascript
运行
复制
void *uploadFileThread(void *arg){ 
    typeArgs* args = (typeArgs*)arg;

   <do something like upload the file>

    *(args->uploadLocker_p) = false;
    free(args);

    return NULL;
    //pthread_exit(0);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-16 14:51:49

创建的线程的默认堆栈大小占用了太多的虚拟内存。

本质上,内核告诉您的进程,它已经使用了这么多虚拟内存,所以它不敢再给它了,因为如果进程突然使用它,就没有足够的RAM和交换来备份它。

若要修复,请创建一个属性,将每个线程堆栈限制为一些合理的属性。如果您的线程不使用数组作为局部变量,或者执行深度递归,那么2*PTHREAD_STACK_MIN (来自<limits.h>)是一个很好的大小。属性不被pthread_create()调用占用,它只是一个配置块,您可以对创建的任意数量的线程使用相同的属性,也可以为每个线程创建一个新的。

示例:

代码语言:javascript
运行
复制
pthread_attr_t  attrs;
pthread_t       tid;
int             err;

pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 2 * PTHREAD_STACK_MIN);
err = pthread_create(&tid, &attrs, uploadFileThread, (void *)args);
pthread_attr_destroy(&attrs);
if (err) {
    /* Failed, errno in err; use strerror(err) */
} else {
    /* Succeeded */
}

还请记住,如果您的uploadFileThread()分配内存,它将不会在线程退出时自动释放。看起来OP已经知道这一点了(因为当函数准备退出时,函数释放了参数结构),但是我认为指出它是个好主意。

就我个人而言,我喜欢使用线程池代替。这个想法是,上传工作人员是预先创建的,他们将等待一个新的工作。下面是一个示例:

代码语言:javascript
运行
复制
pthread_mutex_t        workers_lock;
pthread_mutex_t        workers_wait;
volatile struct work  *workers_work;
volatile int           workers_idle;
volatile sig_atomic_t  workers_exit = 0;

struct work是受workers_lock保护的单链列表时,workers_idle被初始化为零并在等待新工作时增加,workers_wait是当新工作在workers_lock下到达时发出信号的条件变量,而workers_exit是一个计数器,当非零时,指示许多员工退出。

一个工人基本上就是

代码语言:javascript
运行
复制
void worker_do(struct work *job)
{
   /* Whatever handling a struct job needs ... */
}

void *worker_function(void *payload __attribute__((unused)))
{
    /* Grab the lock. */
    pthread_mutex_lock(&workers_lock);

    /* Job loop. */
    while (!workers_exit) {
        if (workers_work) {
            /* Detach first work in chain. */
            struct work *job = workers_work;
            workers_work = job->next;
            job->next = NULL;

            /* Work is done without holding the mutex. */
            pthread_mutex_unlock(&workers_lock);
            worker_do(job);
            pthread_mutex_lock(&workers_lock);
            continue;
        }

        /* We're idle, holding the lock. Wait for new work. */
        ++workers_idle;
        pthread_cond_wait(&workers_wait, &workers_lock);
        --workers_idle;
    }

    /* This worker exits. */
    --workers_exit;

    pthread_mutex_unlock(&workers_lock);
    return NULL;
}

连接处理过程可以使用idle_workers()来检查空闲工作人员的数量,或者增长工作线程池,或者因为太忙而拒绝连接。idle_workers()就像

代码语言:javascript
运行
复制
static inline int  idle_workers(void)
{
    int  result;
    pthread_mutex_lock(&workers_lock);
    result = workers_idle;
    pthread_mutex_unlock(&workers_lock);
    return result;
}

请注意,每个工作人员只在很短的时间内保存锁,因此idle_workers()调用不会阻塞很长时间。(pthread_cond_wait()在开始等待信号时原子地释放锁,并且只有在重新获得锁之后才返回。)

accept()中等待新连接时,设置套接字非阻塞,并使用poll()等待新连接。如果超时已过,请检查工作人员的数量,并在必要时通过调用reduce_workers(1)或类似的方法减少工人数量:

代码语言:javascript
运行
复制
void reduce_workers(int number)
{
    pthread_mutex_lock(&workers_lock);
    if (workers_exit < number) {
        workers_exit = number;
        pthread_cond_broadcast(&workers_wait);
    }
    pthread_mutex_unlock(&workers_lock);
}

为了避免对每个线程调用pthread_join() --我们甚至不知道这里有哪些线程退出了!--为了获取/释放与线程相关的内核和C库元数据,需要分离工作线程。成功创建工作线程tid后,只需调用pthread_detach(tid);即可。

当一个新连接到达并被确定为应该委托给工作线程时,您可以(但不必)检查空闲线程的数量、创建新的辅助线程、拒绝上载或只是将工作附加到队列中,以便“最终”处理它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62409492

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档