c - 用多线程 C 分叉一个进程
问题描述
我正在关注本指南pthread
,fork
但我对以下代码的工作方式感到困惑。以下代码来自https://github.com/angrave/SystemProgramming/wiki/Pthreads%2C-Part-2%3A-Usage-in-Practice
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static pid_t child = -2;
void *sleepnprint(void *arg) {
printf("%d:%s starting up...\n", getpid(), (char *) arg);
while (child == -2) {sleep(1);} /* Later we will use condition variables */
printf("%d:%s finishing...\n",getpid(), (char*)arg);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1,NULL, sleepnprint, "New Thread One");
pthread_create(&tid2,NULL, sleepnprint, "New Thread Two");
child = fork();
printf("%d:%s\n",getpid(), "fork()ing complete");
sleep(3);
printf("%d:%s\n",getpid(), "Main thread finished");
pthread_exit(NULL);
return 0; /* Never executes */
}
8970:New Thread One starting up...
8970:fork()ing complete
8973:fork()ing complete
8970:New Thread Two starting up...
8970:New Thread Two finishing...
8970:New Thread One finishing...
8970:Main thread finished
8973:Main thread finished
- 8970是父进程吗?
- 从网站上,它说孩子只有单线程,所以这是否意味着子进程没有
sleepnprint
运行? - 为什么
8970:fork()ing complete
8973:fork()ing complete
要先打印8970:New Thread Two starting up...
?线程和进程的顺序是随机的吗?
解决方案
主线程(main() 函数)使用pthread_create( ) 创建两个线程,但由于它们是线程,它们是同一进程的一部分(getpid() 为主线程和辅助线程返回 8970)。如果您想要任务标识符,请在线程入口点调用gettid() (您将分别获得 8971 和 8972)。
然后,父进程分叉,父进程和子进程都在 main() 函数中继续。他们分别显示他们的pid:8970和8973。
当一个多线程进程fork时,只有调用线程在子进程中被“复制”(父进程的其他线程不会被fork:子进程是单线程的,直到它在它的一侧创建新线程)。因此,在您的示例中,子进程编号 8973 没有在父进程(编号 8970)中创建的两个线程。
是的,所有线程和进程都并行运行(以任何顺序)。
为了说明前面的内容,这里是您的程序的一个略微增强的版本:
#define _GNU_SOURCE // To get gettid()
#include <pthread.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static volatile pid_t child = -2;
void *sleepnprint(void *arg)
{
printf("Process %d, Task %d:%s starting up...\n", getpid(), gettid(), (char *) arg);
// This is not the best way to synchronize threads but this works here:
// once the main thread returns from fork(), child = pid of child process
// (i.e. != -2)
while (child == -2) {sleep(1);} /* Later we will use condition variables */
printf("Process %d, Task %d:%s finishing...\n", getpid(), gettid(), (char*)arg);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1,NULL, sleepnprint, "New Thread One");
pthread_create(&tid2,NULL, sleepnprint, "New Thread Two");
child = fork();
// In father process: child = child process pid
// In child process: child = 0
if (child == 0) {
// This is the child process
printf("%d:%s\n",getpid(), "Child process finished");
exit(0);
}
// Father process
printf("%d:%s\n",getpid(), "fork()ing complete");
sleep(3);
printf("%d:%s\n",getpid(), "Main thread finished");
pthread_exit(NULL);
return 0; /* Never executes */
}
编译和执行:
$ gcc example.c -l pthread
$ ./a.out
Process 6141, Task 6142:New Thread One starting up...
Process 6141, Task 6142:New Thread One finishing...
Process 6141, Task 6143:New Thread Two starting up...
Process 6141, Task 6143:New Thread Two finishing...
6144:Child process finished
6141:fork()ing complete
6141:Main thread finished
推荐阅读
- python - 如何在 f 字符串中包含 dict 理解?
- aws-serverless - 用于 serverless::api 的 AWS SAM 模板未创建认知用户池授权方
- react-native - 找不到模块“@hmscore/react-native-hms-push”的声明文件
- redirect - 当存在要注销的多个帐户时,使用 SimpleSAMLphp 注销到 Azure AD 中的指定网站后不会发生重定向
- wpf - 获取使用 Prism 进行导航的注册视图列表
- java - Java + MySQL - 加密现有数据
- ruby-on-rails - JSONAPi::可请求的资源限制模型包括
- javascript - 如何将链接推送到 JS 数组?
- confluence - 如何在 Confluence CQL 中添加条件 ORDER BY?
- reactjs - 尝试使用 cmd 为 reactjs 创建一个文件夹