Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux中的线程/进程机制_C_Linux_Multithreading - Fatal编程技术网

C Linux中的线程/进程机制

C Linux中的线程/进程机制,c,linux,multithreading,C,Linux,Multithreading,我的问题是关于PC寄存器的值,它被赋予创建的线程 如果我使用fork()创建一个新进程,PC值将从父进程复制到子进程,因为PC值是代码中的下一个命令 但是,如果我创建一个新线程,如下所示 #include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg)

我的问题是关于PC寄存器的值,它被赋予创建的线程

如果我使用
fork()
创建一个新进程,PC值将从父进程复制到子进程,因为PC值是代码中的下一个命令

但是,如果我创建一个新线程,如下所示

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg)
我只是命令线程运行一个过程,但我不知道创建的线程从哪里得到它的PC值?肯定不是父亲的电脑。如何将PC值设置为doSomeThing代码的第一行?

(大致上)它的PC设置为您提供的函数的地址。实际上,它被设置为调用函数的某个存根。在这个存根中,有一些对系统例程的调用,它设置了支持系统中线程所需的一切。PC的设置方式取决于内核和硬件。如果您对系统代码感到满意,您可以浏览Linux内核源代码,看看这是如何做到的

例如,glibc2.0有一个
start\u thread
函数,它获取系统构建的结构pthread的地址(该例程就是存根)。在该函数中,有一个对某个宏的调用
call\u THREAD\u FCT(THREAD\u struct\u address)
,其目的是开始运行函数。其对i386平台的定义为:

#define CALL_THREAD_FCT (       descr   )   \
({ void *__res;                               \
     int __ignore1, __ignore2;                            \
     asm volatile ("pushl %%eax\n\t"                          \
           "pushl %%eax\n\t"                          \
           "pushl %%eax\n\t"                          \
           "pushl %%gs:%P4\n\t"                       \
           "call *%%gs:%P3\n\t"                       \
           "addl $16, %%esp"                          \
           : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2)         \
           : "i" (offsetof (struct pthread, start_routine)),          \
             "i" (offsetof (struct pthread, arg)));           \
     __res; })

例如,请参见。

其PC值是从传递给要运行线程的
pthread\u create()
的函数的开始处开始的。当该函数返回时,线程退出。这里的“PC寄存器”是指程序计数器寄存器吗?在使用大多数软件包创建线程时,请指定线程启动的函数。寄存器称为PC或IP。当我创建thead时,我给出了指向过程的指针。我试图理解程序代码中第一行的值是如何进入PC的。我的问题是它是如何工作的。。。信息必须保存在某个地方,然后复制到PC。信息保存在哪里?基本上与启动主线程时PC的设置方式相同。主线程实际上是进程,因此创建时不会出现此问题。主线程不是通过将您的PC发送到其他地方创建的。我不是在寻找特定信息,而是更多地了解您编写的“PC设置为您提供的函数的地址”的一般想法。我下面的问题是:此地址保存在哪里?是否有所有函数的所有入口地址表?或者,如果它是计算值-计算时会带来哪些值?例如,请查看glibc中的start_线程函数。调用
call\u THREAD\u函数(您的\u地址)
处理该调用。我从来没有深入研究过这个问题,但我相信你会发现它在你的平台上是如何工作的。是的,所有函数的地址都是已知的!这是在编译时确定的。查看任何可执行文件的符号表(例如,使用
nm
工具)。但是,当编译结束时,符号表就消失了。我可以创建一个线程,其指针指向编译期间未知的函数。在运行时,将知道正确的指针。该指针如何转换到PC寄存器?不,符号表存储在可执行文件中。即使在源代码中引用
func
时它不在那里,编译器也知道函数的地址,然后用它的值替换符号。是的,你可以为一个在编译时地址未知的函数创建一个线程,但这不是你做的方式!extern函数的地址在链接时是已知的,因此在编译/链接时具有未知地址的函数肯定不是您所认为的(当然,我可能是错的)。
#define CALL_THREAD_FCT (       descr   )   \
({ void *__res;                               \
     int __ignore1, __ignore2;                            \
     asm volatile ("pushl %%eax\n\t"                          \
           "pushl %%eax\n\t"                          \
           "pushl %%eax\n\t"                          \
           "pushl %%gs:%P4\n\t"                       \
           "call *%%gs:%P3\n\t"                       \
           "addl $16, %%esp"                          \
           : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2)         \
           : "i" (offsetof (struct pthread, start_routine)),          \
             "i" (offsetof (struct pthread, arg)));           \
     __res; })