为了测试错误恢复,我想让
pthread_create
以可预测的方式失败。最明显的方法是对特定进程中允许存在的线程数设置硬性上限。
特别是在 Linux 上,
setrlimit(RLIMIT_NPROC)
会影响进程和线程的创建;将限制设置为 1 将导致 pthread_create
在 setrlimit
调用之后的任何代码都失败。 Solaris 衍生的 Unixes [我只测试了 OmniOS r151030] 没有 RLIMIT_NPROC,但确实有办法通过更精美的 setrctl
接口来限制进程中的线程数量。
在我尝试过的任何其他 Unix 上,我都无法找到从 C 语言执行此操作的方法。特别是,这个问题底部的测试程序将在所有(AIX 7.1、FreeBSD 12.1、NetBSD 9.3、OpenBSD 6.8)上打印“fail: pthread_create successed”。
所以,问题是:请修改测试程序,使
pthread_create
调用在一个或多个既不是 Linux 也不是 Solaris 的 Unix 上失败。首选适用于“多种”Unix 的答案(例如,如果您可以展示一种在“所有”BSD 派生系统上执行此操作的方法,那就太好了)。
注意:除了实际执行测试程序的进程之外,会对其他进程产生副作用的答案(例如,对特定 uid 或整个系统下运行的线程总数施加限制)对我来说没有好处。
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
static void *threadproc(void *arg)
{
puts("fail: pthread_create succeeded");
return arg;
}
int main(void)
{
struct rlimit r = { 1, 1 };
if (setrlimit(RLIMIT_NPROC, &r)) {
perror("error: setrlimit failed");
return 1;
}
pthread_t t;
int err = pthread_create(&t, 0, threadproc, 0);
if (err) {
printf("ok: pthread_create failed (%s)\n", strerror(err));
return 0;
}
err = pthread_join(t, 0);
if (err)
printf("error: pthread_join failed (%s)\n", strerror(err));
return 1;
}
AIX setrlimit()
:RLIMIT_THREADS 每个进程可以创建的最大线程数。此限制由内核和 pthread 调试库强制执行。
只需更换
setrlimit(RLIMIT_NPROC, &r)
与
setrlimit(RLIMIT_THREADS, &r)
(但是,我无法访问 AIX 实例进行测试)
BSDBSD 似乎没有任何不依赖于每个用户或整个系统限制的等价物。
您可以使用 POSIX 函数保护堆栈内存
int mprotect(void *addr, size_t len, int prot);
类似这样的:
pthread_attr_t attr;
// attr initialization here:
int rc;
void *mystack;
size_t mystacksize = 2 * PTHREAD_STACK_MIN;
if (pthread_attr_init(&attr) < -1) {
perror("error in pthread_attr_init");
return -1;
}
// Get a big enough stack and align it on 4K boundary.
mystack = malloc(PTHREAD_STACK_MIN * 3);
if (!mystack) {
perror("Unable to acquire storage.");
return -1;
}
// Align stack, memory leak is possible
mystack = (((intptr_t)mystack) & 0xfff)
? (void*)( ( ((intptr_t)mystack) & 0xfff) + 0x1000): mystack;
rc = pthread_attr_setstack(&attr, mystack, mystacksize);
if (rc != 0) {
perror("pthread_attr_setstack()");
return -1;
}
// Protect stack memory:
rc = memprotect(stack, mystacksize, PROT_NONE);
if (rc) {
perror("mprotect()");
return -1;
}
pthread_t t;
// Should fail, cause stack memory is protected
int err = pthread_create(&t, attr, threadproc, 0);
if (err) {
printf("ok: pthread_create failed (%s)\n", strerror(err));
return 0;
}