Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何解决pthread_创建错误(11)资源暂时不可用?_C_Linux_Multithreading_Pthreads_Openwrt - Fatal编程技术网

C 如何解决pthread_创建错误(11)资源暂时不可用?

C 如何解决pthread_创建错误(11)资源暂时不可用?,c,linux,multithreading,pthreads,openwrt,C,Linux,Multithreading,Pthreads,Openwrt,我正在用c语言构建一个项目(使用openwrt作为操作系统)将文件上传到FTP服务器。我对传入的数据使用MQTT。因此,对于我订阅的每个主题,我保存这些数据,然后将其上传到FTP服务器,为了保持事情的顺利进行,每次我需要上传一个文件时,我只使用一个线程来完成这项工作。 为了确保程序不会运行太多线程,允许每个主题创建一个线程。我使用了一个变量(比如mutex,但它不是pthread\u mutex\t,因为我不需要阻止线程,我想跳过这一步并上传下一个文件)。我认为使用这种技术我是安全的,但是在运行

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

  • 我使用了pthread_join()函数,这在我的条件下不是一个选项,只是为了确保每个线程都已完成,并且没有在永久循环中运行。程序运行了一个多小时,错误没有再次出现。当然,每一根线都是按预期完成的
  • 我90%确信每个主题只在线程上创建,下一个主题只有在前一个主题完成后才会创建。(我正在跟踪线程创建前后变量的状态)
  • 我从这里将max thread“/proc/sys/kernel/threads max”设置为2000(2000已经足够了,因为我没有太多的主题)
上载功能(这将创建线程):

void上传文件(,bool*locker\p){
*locker_p=真;
args->uploadLocker\u p=uploadLocker\u p;
pthread_t tid;
int error=pthread_create(&tid,NULL,uploadFileThread,(void*)参数);
如果(0!=错误){
printf(“无法运行线程,(%d)=>%s\n”,错误,strerror(错误));
}
否则{
printf(“线程%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);
}
void*上传文件线程(void*arg){
typeArgs*args=(typeArgs*)arg;
*(args->uploadLocker\u p)=错误;
免费(args);
返回NULL;
//pthread_退出(0);
}

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

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

要修复此问题,请创建一个属性,将每线程堆栈限制为合理的值。如果您的线程不使用数组作为局部变量,或者不执行深度递归,那么
2*PTHREAD\u STACK\u MIN
(来自
)是一个不错的大小。 该属性不被
pthread_create()
调用使用,它只是一个配置块,您可以对创建的任意数量的线程使用相同的属性,也可以为每个线程创建一个新的属性

例如:

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已经知道了这一点(因为当它准备退出时,他们有无函数的参数结构),但我认为指出这一点是个好主意


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

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\u lock
保护的单链列表,
workers\u idle
初始化为零,并在等待新工作时递增,
workers\u wait
是在
workers\u lock
下到达新工作时发出信号的条件变量,而
workers\u exit
是一个计数器,当非零时,它会告诉许多worker退出

一个工人基本上是一个好东西

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()
检查空闲工作线程的数量,或者增加工作线程池,或者因为太忙而拒绝连接。
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_cond_wait()
在开始等待信号时自动释放锁,并且仅在重新获取锁后返回。)

accept()
中等待新连接时,将套接字设置为非阻塞,并使用
poll()
等待新连接。如果超时时间已过,请检查工作人员的数量,如有必要,可通过调用
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);
}
void reduce\u workers(整数)
{
pthread_mutex_lock(&workers_lock);
如果(工人退出<数量){
工人退出=数量;
pthread_cond_广播(&workers_wait);
}
pthread_mutex_unlock(&workers_lock);
}
为了避免为每个线程调用
pthread\u join()
,我们甚至不知道哪些线程已经退出了这里要获取/释放与线程相关的内核和C库元数据,需要分离工作线程。成功创建工作线程
tid
后,只需调用
pthread\u detach(tid)


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

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

本质上,内核是在告诉您的进程,它已经有太多的虚拟内存在使用,它不敢再给它了,因为没有足够的RAM和交换来备份它
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);
}