- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如果这个问题很愚蠢,请道歉。我试图在网上找到答案已经有一段时间了,但不能,因此我在这里问。我正在学习线程,我一直在经历 this link和 this Linux Plumbers Conference 2013 video关于内核级和用户级线程,据我所知,使用 pthreads 在用户空间中创建线程,内核不知道这一点,只将其视为单个进程,不知道内部有多少线程。在这种情况下,
clone()
也是如此系统调用创建内核级线程或用户级线程?strace
一个简单的 pthreads program还显示了在执行时使用 clone(),但是为什么它会被视为用户级线程? 最佳答案
这是由最高评论开始的。
您正在阅读的文档是通用的 [不是特定于 linux 的] 并且有点过时。而且,更重要的是,它使用了不同的术语。我相信,这就是困惑的根源。所以,请继续阅读...
它所谓的“用户级”线程就是我所说的 [过时] LWP 线程。它所谓的“内核级”线程就是Linux中所谓的 native 线程。在 linux 下,所谓的“内核”线程完全是另一回事 [见下文]。
using pthreads create threads in the userspace, and the kernel is not aware about this and view it as a single process only, unaware of how many threads are inside.
NPTL
之前完成用户空间线程的方式( native posix 线程库)。这也是 SunOS/Solaris 所说的
LWP
轻量级工艺。
glibc
中的 pre-NPTL 实现还必须[强行]抢占 LWP 线程(即实现时间切片)。我不记得使用的确切机制,但是,这里有一个例子。线程主必须设置闹钟,进入休眠状态,唤醒然后向事件线程发送信号。信号处理程序会影响上下文切换。这是凌乱的,丑陋的,有点不可靠。
Joachim mentioned
pthread_create
function creates a kernel thread
pthread_create
创建一个本地线程。它在用户空间中运行,并在与进程平等的基础上争夺时间片。一旦创建,线程和进程之间几乎没有区别。
If it doesn't create a kernel level thread, then how are kernel threads created from userspace programs?
kernel_thread
创建。功能。它们作为内核的一部分运行,不与任何用户空间程序/进程/线程相关联。他们可以完全访问机器。设备、MMU 等 内核线程运行在最高权限级别:ring 0。它们也在内核的地址空间中运行,而不是在任何用户进程/线程的地址空间中运行。
pthread_create
创建了一个本地线程。 ,它调用
clone
系统调用这样做。
ps ax
来查看这些线程。 .看你就会看到
kthreadd, ksoftirqd, kworker, rcu_sched, rcu_bh, watchdog, migration
等。这些是内核线程,而不是程序/进程。
You mentioned that kernel doesn't know about user threads.
fork
系统调用。
pthreads
和
clone
系统调用。现在,
fork
实现为
clone
.
clone
类似于
fork
但需要一些论据。值得注意的是,
flags
参数和
child_stack
争论。
then, how is it possible for user level threads to have individual stacks?
%rsp
. x86 有
push
和
pop
指示。我们用这些来保存和恢复东西:
push %rcx
和 [稍后]
pop %rcx
.
%rsp
或
push/pop
指示?我们还能有一个堆栈吗?当然,按照惯例。我们 [作为程序员] 同意(例如)
%rbx
是堆栈指针。
%rcx
将是 [使用 AT&T 汇编程序]:
subq $8,%rbx
movq %rcx,0(%rbx)
%rcx
的“流行”将是:
movq 0(%rbx),%rcx
addq $8,%rbx
// push %ecx
%rbx -= 8;
0(%rbx) = %ecx;
// pop %ecx
%ecx = 0(%rbx);
%rbx += 8;
malloc
创建一个堆栈区域。 .然后它必须将此指针保存在每个线程的结构中,然后启动子 LWP。实际代码有点棘手,假设我们有一个(例如)
LWP_create
类似于
pthread_create
的功能:
typedef void * (*LWP_func)(void *);
// per-thread control
typedef struct tsk tsk_t;
struct tsk {
tsk_t *tsk_next; //
tsk_t *tsk_prev; //
void *tsk_stack; // stack base
u64 tsk_regsave[16];
};
// list of tasks
typedef struct tsklist tsklist_t;
struct tsklist {
tsk_t *tsk_next; //
tsk_t *tsk_prev; //
};
tsklist_t tsklist; // list of tasks
tsk_t *tskcur; // current thread
// LWP_switch -- switch from one task to another
void
LWP_switch(tsk_t *to)
{
// NOTE: we use (i.e.) burn register values as we do our work. in a real
// implementation, we'd have to push/pop these in a special way. so, just
// pretend that we do that ...
// save all registers into tskcur->tsk_regsave
tskcur->tsk_regsave[RAX] = %rax;
// ...
tskcur = to;
// restore most registers from tskcur->tsk_regsave
%rax = tskcur->tsk_regsave[RAX];
// ...
// set stack pointer to new task's stack
%rsp = tskcur->tsk_regsave[RSP];
// set resume address for task
push(%rsp,tskcur->tsk_regsave[RIP]);
// issue "ret" instruction
ret();
}
// LWP_create -- start a new LWP
tsk_t *
LWP_create(LWP_func start_routine,void *arg)
{
tsk_t *tsknew;
// get per-thread struct for new task
tsknew = calloc(1,sizeof(tsk_t));
append_to_tsklist(tsknew);
// get new task's stack
tsknew->tsk_stack = malloc(0x100000)
tsknew->tsk_regsave[RSP] = tsknew->tsk_stack;
// give task its argument
tsknew->tsk_regsave[RDI] = arg;
// switch to new task
LWP_switch(tsknew);
return tsknew;
}
// LWP_destroy -- destroy an LWP
void
LWP_destroy(tsk_t *tsk)
{
// free the task's stack
free(tsk->tsk_stack);
remove_from_tsklist(tsk);
// free per-thread struct for dead task
free(tsk);
}
pthread_create
和
clone
,但我们仍然需要创建新线程的堆栈。内核不会为新线程创建/分配堆栈。
clone
系统调用接受
child_stack
争论。因此,
pthread_create
必须为新线程分配一个堆栈并将其传递给
clone
:
// pthread_create -- start a new native thread
tsk_t *
pthread_create(LWP_func start_routine,void *arg)
{
tsk_t *tsknew;
// get per-thread struct for new task
tsknew = calloc(1,sizeof(tsk_t));
append_to_tsklist(tsknew);
// get new task's stack
tsknew->tsk_stack = malloc(0x100000)
// start up thread
clone(start_routine,tsknew->tsk_stack,CLONE_THREAD,arg);
return tsknew;
}
// pthread_join -- destroy an LWP
void
pthread_join(tsk_t *tsk)
{
// wait for thread to die ...
// free the task's stack
free(tsk->tsk_stack);
remove_from_tsklist(tsk);
// free per-thread struct for dead task
free(tsk);
}
malloc
为提议的线程预先分配区域。 .旁注:使用
malloc
是正常方式,但线程创建者可能只有一个大的全局内存池:
char stack_area[MAXTASK][0x100000];
如果它想那样做。
malloc
以及上面的汇编技巧,如果它正在执行一个巨大的递归函数,它就会创建一个更大的堆栈。
关于c++ - 用户级线程是如何调度/创建的,内核级线程是如何创建的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39185134/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!