【问题标题】:How to pass template function to POSIX threading (pthread)如何将模板函数传递给 POSIX 线程(pthread)
【发布时间】:2021-02-09 23:07:58
【问题描述】:

我在使用带有 POSIX 线程的模板函数时遇到了麻烦。 作为编程语言,我使用 C++98,作为线程基础架构,我使用 POSIX 线程 (<pthread.h>)。

我的环境不支持标准线程 (<thread>)

通常,我们可以将参数传递给 pthreads,如下所示:

#include <stdio.h>
#include <pthread.h>

void * hello(void *input) {
    printf("%s\n", (char *)input);
    pthread_exit(NULL);
}

int main(void) {
    pthread_t tid;
    pthread_create(&tid, NULL, hello, "hello world");
    pthread_join(tid, NULL);
    return 0;
}

问题是,如何将模板函数和参数传递给 pthreads?

这里是示例模板函数:

#include <pthread.h>

template<class T>
void *hello(T val){
    SampleInterface *interface = &T;
    cout << interface->Message<<endl;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    pthread_create(&tid, NULL, hello, sClass);
    pthread_join(tid, NULL);
    return 0;
}

如果我使用上述用法,我会收到两个错误:

error: no matches converting function 'hello' to type 'void* (*)(void*)'
error: candidates are: template<class T> void* hello(T)

【问题讨论】:

  • 替代方案:从void * (void *)函数内部调用模板化函数。
  • 感谢您的评论。你的意思是调用“hello”函数吗?如果是,它不能解决我的问题。最后,我必须将 T 参数传递给这个函数。
  • 问题可能源于编译器无法从pthread_create(&amp;tid, NULL, hello, sClass); 推断出T。但重点是没有意义的。 pthread_create 想要一个函数,该函数接受 void 指针并返回 void 指针。给它任何其他东西,你就会试探命运。
  • 是的,也许您对“问题可能源于编译器无法推断”评论是正确的。尽管如此,我还是无法理解如何做到这一点:/
  • 我不认为我可以正式回答这个问题而不冒帮助您挖一个更深的洞的风险。 hello 需要看起来像 template&lt;class T&gt; void *hello(void * userp) 并且将被称为 pthread_create(&amp;tid, NULL, hello&lt;SampleClass&gt;, &amp;sClass);,但这需要 hello 包含一些类似 SampleInterface *interface = (T *)userp; 的代码,我不确定这是正确的决定。

标签: c++ multithreading pthreads c++98


【解决方案1】:

由于你不是直接调用hello(),编译器无法为你推导出模板参数,所以你必须显式指定模板参数。

您还需要更改 hello() 以匹配 pthread_create() 所期望的签名(就像您的非模板示例一样),除非您在将函数传递给 pthread_create() 的位置对函数进行类型转换(我不建议这样做,因为它在技术上是未定义的行为,但它在某些编译器中确实有效)。

试试这个:

#include <iostream>
#include <pthread.h>

template<class T>
void *hello(void *arg){
    T *val = static_cast<T*>(arg);
    SampleInterface *interface = val;
    cout << interface->Message << endl;
    return NULL;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    pthread_create(&tid, NULL, hello<SampleClass>, &sClass);
    pthread_join(tid, NULL);
    return 0;
}

或者:

#include <iostream>
#include <pthread.h>

typedef void* (*pthread_callback_t)(void*);

template<class T>
void *hello(T *val){
    SampleInterface *interface = val;
    cout << interface->Message << endl;
    return NULL;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    pthread_create(&tid, NULL, reinterpret_cast<pthread_callback_t>(hello<SampleClass>), &sClass);
    pthread_join(tid, NULL);
    return 0;
}

或者,您根本不需要示例中的模板,因此您可以稍微简化代码:

#include <iostream>
#include <pthread.h>

void *hello(void *arg){
    SampleInterface *interface = static_cast<SampleInterface*>(arg);
    cout << interface->Message << endl;
    return NULL;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    SampleInterface *interface = &sClass;
    pthread_create(&tid, NULL, hello, interface);
    pthread_join(tid, NULL);
    return 0;
}

或者:

#include <iostream>
#include <pthread.h>

typedef void* (*pthread_callback_t)(void*);

void *hello(SampleInterface *interface){
    cout << interface->Message << endl;
    return NULL;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    SampleInterface *interface = &sClass;
    pthread_create(&tid, NULL, reinterpret_cast<pthread_callback_t>(hello), interface);
    pthread_join(tid, NULL);
    return 0;
}

【讨论】:

  • "static_cast" 随 C++11 一起提供。所以,我不能使用这种方法(我使用的是 C++98)。这种方法很好。让我们试试吧。
  • "static_cast 随 C++11 提供" - 不,它没有。大多数 C++ 风格转换都存在于 C++98 中,包括 static_castreinterpret_cast。 C++11 确实添加了一些新的转换,但它们是特定于 std::shared_ptr 的。但是,即使您碰巧使用的是不支持static_cast 的 C++98 编译器,您也可以只使用 C 样式转换,例如:T *val = (T*)arg;SampleInterface *interface = (SampleInterface*)arg;(pthread_callback_t)hello&lt;SampleClass&gt;、@987654336 @等
  • 对于此代码部分 " pthread_create(&amp;tid, NULL, reinterpret_cast&lt;pthread_callback_t&gt;(hello), interface);" ,我收到 "error: invalid use of member (did you forget the '&amp;' ?)" 错误。
  • hello() 是一个类的非静态方法吗?如果是这样,则不能对 pthread 使用非静态方法,因为非静态方法具有隐式 this 参数。您必须使用静态方法或独立函数来摆脱this 参数。但是,如果hello() 需要访问非静态成员,您可以将类对象的this 指针传递给pthread_create()arg 参数。
  • 哦,是的,你是对的。我忘了放静态关键字。现在,它完美运行。非常感谢您的支持。
【解决方案2】:
#include <stdio.h>
#include <pthread.h>
#include <iostream>

struct SampleInterface {
    int Message;
};

struct SampleClass : public SampleInterface {
    SampleClass() {
        Message = 42;
    };
};

template<class T>
void *hello(void* input){
    SampleInterface *interface = (T*) input;
    std::cout << interface->Message << std::endl;
    pthread_exit(NULL);
    return NULL;
}

int main(void) {
    pthread_t tid;
    SampleClass sClass;
    SampleInterface* pInterface = &sClass; //see  Remy Lebeau's comment why we should not pass sClass directly to pthread create
    pthread_create(&tid, NULL, hello<SampleInterface>, (void*) pInterface);
    pthread_join(tid, NULL);
    return 0;
}

编译并运行,尝试在此处粘贴此代码示例 http://cpp.sh/

【讨论】:

  • 当我使用你提到的"template&lt;class T&gt;" for "hello"函数时,我的编译器给出"error: candidates are: template&lt;class T&gt; void* hello(T)"错误。
  • @MahmutEFE 该错误表明您没有将hello 的输入参数从T 更改为void* 以匹配pthread_create() 接受的参数。仔细查看您给出的示例。
  • @HappyKeyboard 您正在通过 void* 传递一个 SampleClass* 指针,其中应该是 SampleInterface*。由于类型不匹配,这在技术上是未定义的行为。 C++ 标准仅保证在将void* 转换为与void* 相同的类型时从void* 获取有效指针。因此,要解决此问题,您必须 1) 使用 hello&lt;SampleClass&gt;,2) 将 &amp;sClass 转换为 SampleInterface*,然后将其传递给 hello&lt;SampleInterface&gt;,或者 3) 将 hello&lt;SampleInterface&gt; 更改为将 input 转换为 @ 987654340@ 在转换为 SampleInterface* 之前。
  • @RemyLebeau 好点。我猜@Mahmut EFE 想要方法hello 只想使用指向接口的指针。相应地更新代码,并引用评论部分以获得信用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 2014-03-11
  • 1970-01-01
  • 2017-12-25
  • 2021-07-30
  • 1970-01-01
  • 2017-05-25
相关资源
最近更新 更多