【发布时间】:2019-04-29 13:32:40
【问题描述】:
有时当我尝试使用 pthread_key_create 创建密钥时,我会收到 EAGAIN 错误代码。有可能确切地知道原因吗?
文档说:
系统缺乏必要的资源来创建另一个特定于线程的数据键,或者系统对每个进程的键总数 [PTHREAD_KEYS_MAX] 施加的限制将被超出。
如何检查它是否是键的限制?或许是某种监控工具之王来检查系统中已经打开了多少个密钥,还有多少个还可以使用?
关于我们的代码有一个重要的事情:我们使用fork() 并且有多个进程在运行。每个进程可以有多个线程。
我发现当我们使用fork()时,我们对线程键没有独立的限制。这是一个小例子。
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
size_t create_keys(pthread_key_t *keys, size_t number_of_keys)
{
size_t counter = 0;
for (size_t i = 0; i < number_of_keys; i++)
{
int e = pthread_key_create(keys + i, NULL);
if (e)
{
printf("ERROR (%d): index: %ld, pthread_key_create (%d)\n", getpid(), i, e);
break;
}
counter++;
}
return counter;
}
int main(int argc, char const *argv[])
{
printf("maximim number of thread keys: %ld\n", sysconf(_SC_THREAD_KEYS_MAX));
printf("process id: %d\n", getpid());
const size_t number_of_keys = 1024;
pthread_key_t keys_1[number_of_keys];
memset(keys_1, 0, number_of_keys * sizeof(pthread_key_t));
printf("INFO (%d): number of active keys: %ld\n", getpid(), create_keys(keys_1, number_of_keys));
pid_t p = fork();
if (p == 0)
{
printf("process id: %d\n", getpid());
pthread_key_t keys_2[number_of_keys];
memset(keys_2, 0, number_of_keys * sizeof(pthread_key_t));
printf("INFO (%d): number of active keys: %ld\n", getpid(), create_keys(keys_2, number_of_keys));
}
return 0;
}
当我在 Ubuntu 16.04 上运行此示例时,我发现如果我使用与限制 (1024) 相同数量的键,子进程将无法创建任何新的线程键。但是,如果我对父进程和子进程使用 512 键,我可以毫无错误地运行它。
【问题讨论】:
-
假设您的意思是
PTHREAD_KEYS_MAX,它在<limits.h>中定义。您可以通过每次递增一个原子 int 轻松跟踪您调用pthread_key_create()的次数,然后在收到该错误后比较这两个值。不过,在我的系统上是 1024。你为什么要创建这么多不同的线程局部变量?似乎不对。显示您的代码;我敢打赌,您尝试使用它们的方式有问题。 -
@Shawn 是的,我们创建了许多进程(Apache + fork),每个进程可以有许多线程。所以使用原子计数器不是一个好主意,因为我需要在所有进程中都有这样的计数器。
-
嗯?进程数无关紧要;每个人都有自己的一套钥匙。进程中的线程数也无关紧要。重要的是特定进程具有的线程本地存储密钥的数量。对于线程特定数据的概念,您肯定有一些不了解的地方。显示minimal reproducible example。
-
@Shawn 我为
fork()创建了一个小例子,看起来进程数很重要。 -
您的子进程在使用 1024 时无法再创建任何密钥,因为父进程在分叉之前已经创建了最大数量...