我希望在C语言中实现多线程,但不使用任何POSIX库。
注:请勿使用fork()或vfork()。
我希望在C语言中实现多线程,但不使用任何POSIX库。
注:请勿使用fork()或vfork()。
在Linux中,线程本质上是与其父进程共享内存和资源的进程。Linux内核不区分进程和线程,换句话说,Linux中没有像其他操作系统中那样轻量级进程的概念。Linux中的线程被实现为标准进程,因此可以仅使用clone()
创建线程,通常可通过以下方式调用fork()
:
clone(SIGCHLD, 0);
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
这与先前的调用相同,唯一不同之处在于两个进程共享地址空间、文件系统资源、文件描述符和信号处理程序。
另一种方法是使用用户级线程(也称为纤程),它们是在用户级别实现的执行线程,这意味着操作系统不知道这些线程,调度或上下文切换必须在用户级别进行。大多数用户级调度程序都是协作式调度程序,但也可以使用简单的轮询调度实现抢占式调度程序。
查看clone(2)手册以获取详细信息,如果您需要更多信息,我建议阅读罗伯特·洛夫(Robert Love)的Linux Kernel Development第三版(与作者无关),其中有一个内部查看链接,您可以在线阅读部分内容。至于用户级线程,我编写了一个名为libutask的最小包,实现了协作和抢占式调度程序,如果您愿意,可以检查源代码。
注1:我没有提到UNIX,据我所知,这是Linux特定的实现。
注2:使用clone创建自己的线程不是真正的解决方案,请阅读评论以了解可能需要处理的一些问题,它只是回答了一个问题,即是否可以在不使用pthread的情况下创建线程,在这种情况下答案是肯定的。
clone
将不起作用,除非您避免使用任何(直接或间接)调用标准库。这是因为即使像读/写errno
这样基本的事情也会访问相对于线程指针/线程描述符结构的线程本地存储,如果您自己调用clone
,则这些内容将不会被初始化或指向任何有效内容。 - R.. GitHub STOP HELPING ICE参见:
适用于类UNIX系统。
还可以参见:
适用于BSD和现代UNIX。
这个页面提供了使用这些基元和更多内容的许多基本实现示例。
您可以使用原子指令来实现锁定原语(互斥锁,信号量)。
我还建议查看用户空间线程库的实际实现,以获取一些提示。请参见此页面,其中列出了Linux的实现列表。
最后,您可能需要获取有关协程和也许trampolines的一些信息,尽管后者与之不太相关。
longjmp()
手动实现线程是一个非常糟糕的建议。 - user529758sigaltstack
和 raise
来缓解这个问题。显然,GNU Pth 使用了这种技术。既然你提到了这个问题,我会在我的答案中添加必要的系统调用。谢谢! - didierc<threads.h>
头文件。(C11)int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
,以及互斥函数和条件变量。在几乎任何操作系统上,使用纯 c 语言可以构建至少一个协作式微内核。基本上只需要克隆栈帧(并相应地调整一些指针,特别是从函数返回到其他线程当前返回地址的返回地址)。还需要一些实用程序函数,例如“上下文切换”堆栈到堆和反向操作。
如果允许定时器中断带有回调,则可以执行抢占式微内核。
至少 Dr Dobbs 和 IOCCC 提出了这些方案。