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

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

甄胡非
2023-03-14

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

  • 我使用了pthread\u join()函数,这在我的条件下不是一个选项,只是为了确保每个线程都已完成,并且没有在永久循环中运行。程序运行了一个多小时,错误没有再次出现。当然,每根线都按预期完成了

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

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);
    }
}

上载线程:

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);
}

共有1个答案

柳星晖
2023-03-14

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

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

要修复,请创建一个属性,将每个线程的堆栈限制为合理的。如果您的线程不使用数组作为局部变量,或者进行深度递归,那么2*PTHREAD_STACK_MIN(来自

例子:

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 */
}

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

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

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是一个计数器,当非零时,告诉许多工作人员退出。

一个工人基本上就是

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\u workers()检查空闲工作线程的数量,或者增加工作线程池,或者因为太忙而拒绝连接。空闲的工作者()类似于

static inline int  idle_workers(void)
{
    int  result;
    pthread_mutex_lock(&workers_lock);
    result = workers_idle;
    pthread_mutex_unlock(&workers_lock);
    return result;
}

请注意,每个worker只在很短的时间内持有锁,因此调用idle\u workers()不会阻塞很长时间。(pthread\u cond\u wait()在开始等待信号时自动释放锁,并且仅在重新获取锁后返回。)

在接受中等待新连接时,请将套接字设置为非阻塞,并使用轮询等待新连接。如果超时时间已过,请检查工作人员的数量,如有必要,请调用reduce\u workers(1)或类似命令来减少工作人员的数量:

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\u join(),我们甚至不知道这里有哪些线程退出要获取/释放与线程相关的内核和C库元数据,需要分离工作线程。成功创建工作线程tid后,只需调用pthread\u detach(tid)

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

 类似资料:
  • 以下是错误日志: 这里有一个相关的问题:https://stackoverflow.com/a/14370767,它建议使用SO_SNDTIMEO套接字选项设置发送超时。

  • 我在C中使用tcp套接字服务器和客户端。使用AF_INET、SOCK_STREAM和IPPROTO_TCP 在sock send()命令上有一个可能导致“资源暂时不可用”的帖子,其中Davide Berra说 这是因为您使用的是非阻塞套接字,并且输出缓冲区已满。 从send()手册页

  • 创建套接字 使其非阻塞 呼叫连接 按预期返回-1和errno EINPROGRESS 调用select 返回>0,因此已建立连接 再次阻塞套接字 此部件的代码如下: 那还行。但是我有一个循环,在这个循环中我调用了一个函数,该函数检查是否收到了要读取的新数据包:

  • 我有一个伪终端从机,它给我一个资源暂时不可用的读/写错误(11)。我一直无法解决这个问题,但直到一周前我还不知道任何事情。所以,我可能漏掉了一些明显的东西。 根据我所了解的情况,这可能是由对非阻塞PTY调用引起的。但是,当我检查从pty的I之后的时,该值显示它是一个阻塞文件描述符。 我甚至尝试将视为非阻塞文件,使用来确定它何时就绪。但是,它只是每次都超时。 那么,如果设置为blocking,为什么

  • 本文向大家介绍Ubuntu E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用),包括了Ubuntu E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用)的使用技巧和注意事项,需要的朋友参考一下 Ubuntu 18.04,其他版的Ubuntu也一样 问题: 当运行sudo a