为什么pthread_create函数将线程函数名称作为参数而不是调用它?

时间:2013-09-02 20:33:35

标签: c

在我的计划中,对pthread_create的调用如下:

res = pthread_create(&a_thread, NULL, thread_fn, (void*)n);

我的问题是,为什么我们不能成功:

res = pthread_create(&a_thread, NULL, thread_fn( (void*)n) );

因为这会减少pthread_create中的参数数量并且看起来也是合乎逻辑的,因为我只学习了3件事:声明,定义和调用。

将函数名称作为参数传递并添加到将其参数作为单独参数传递的内容是我不明白的事情。

如果这种格式背后有任何逻辑,请解释一下。

3 个答案:

答案 0 :(得分:8)

最明显的论点是你不能将thread_fn“作为一个参数”,因为它需要在 pthread_create被调用之前运行完成 - 也就是说,您将在当前线程中运行发往新线程的代码。

另一种看待事物的方法是创建一个执行线程必须使用OS(内核)代码;操作系统需要在新线程有效使用之前设置其内部簿记结构。由pthread_create引起的内核调用需要知道要在线程中执行的代码的内存地址,以便在设置完所有内容后传递控制到该位置,并传递地址(与其返回值相反)是使用第一种语法完成的。

答案 1 :(得分:1)

  

res = pthread_create(& a_thread,NULL, thread_fn((void *)n));

请记住,粗体部分是函数调用。 C语言的语义调用执行该函数调用,然后将其返回值替换为它的位置。因此,这种语法等同于以下序列。

  1. temp = thread_fn((void *)n)//函数调用
  2. res = pthread_create(& a_thread,NULL,temp)
  3. 这显然不是你想要的。你想要的是函数pthread_create首先创建一个单独的执行线程,它使用你指定的参数执行函数调用thread_fn。

    以下是pthread_create需要做的事情。

    1. 创建新的线程执行上下文。
    2. 设置thread_fn的调用上下文,即设置堆栈和参数等。
    3. 安排输入thread_fn。
    4. 因为函数thread_fn以延迟方式执行,所以唯一的方法是将函数入口点及其参数放在一边,然后安排执行它。这就是为什么这些作为参数传递给pthread_create。

答案 2 :(得分:0)

当你将函数作为函数调用的参数调用时,实际发生的是调用该函数并将return value放在堆栈上以传递给你正在调用的函数。

strthings(getStr1(), strlen(getStr1()), getStr2(), strlen(getStr2()));

转换为(顺序可能因编译器/ cpu而异)

auto t1 = getStr2();   // probably not exact order
auto t2 = strlen(t1);
auto t3 = getStr1();
auto t4 = strlen(t3);
strthings(t3, t4, t1, t2);

所以 - 你的代码:

*res = pthread_create   (&a_thread , NULL , thread_fn( (void*)n) )

会转换为

// run the thread function and get the return value.
auto t1 = thread_fn((void*n));
*res = pthread_create(&a_thread, NULL, t1);

我们将在OUR线程上下文中运行thread_fn,然后传递它的返回值。听起来你期望将函数作为参数传递给被调用的函数并进行内联解释?

为什么传递函数和参数有效?

---编辑:解释为什么单独传递函数和参数。

在C中,函数名实际上是指针变量。指针的类型取决于函数的“指纹”。

int strncmp(const char* left, const char* right, int maxlen);

实际上是

int (*strncmp)(const char*, const char*, int);

也就是说,strncmp是一个指向函数的指针,该函数返回一个void并获取指定类型的三个参数。

这形成了一个契约,所以当你写

int n = strncmp(a, b, 3);

它知道在[presudo]汇编中做一些事情,如:

push a
push b
push 3
call 0x783af83  // strncmp
mov  return -> n
pop  12

所以 - 现在您知道函数实际上是指针(代码),您可以看到如何传递它们,以便您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int func1() { return 1; }
int func2() { return 22; }

int flip(int useFirst, int (*first)(), int (*second)()) {
    return (useFirst) ? first() : second();
}

int main() {
    srand(time(NULL));
    int useFirst = rand() % 2;
    int result = flip(useFirst, func1, func2);
    printf("use first is %u. return value was %u.\n", useFirst, result);
}