我有一个类可以处理与特定硬件的所有通信。硬件需要通过一个套接字更新数据,并在已知(和硬编码)多播地址上广播其 IP 以进行握手。
结果,该类产生了两个线程,一个线程处理与硬件的直接通信并根据该类的成员结构更新数据。另一个线程持续监控组播地址,看IP是否发生了变化。
两个线程都作为类内部的静态成员函数实现。但是,为了使用 pthread,我的理解是它们需要声明为 extern "C"。也就是说,根据我的研究,不可能将类的成员函数声明为外部“C”。我从之前参与该项目的工程师那里看到的一些代码解决了这个问题的方式是线程函数实现被包围在 extern "C" 中。即在函数声明或定义中没有extern "C",而是将整个函数定义封装在extern "C" {}中。
像这样:
extern "C" {
// function goes here
}
我有几个关于这个实现的问题,因为我希望提高对代码的理解并在多线程编程方面做得更好。
考虑到它的实现方式,外部“C”实际上会做任何事情吗?我在这里阅读了修饰符的实际作用:In C++ source, what is the effect of extern "C"? 但是在这种情况下,考虑到我们正在处理作为类的静态成员的函数这一事实,它是否真的适用?
线程成员函数似乎通过执行 reinterpret_cast 并创建指向类的指针来绕过修改类的成员变量的事实。这是标准做法吗,因为当我看到那个演员表时我的红旗被举起?
构造函数调用 pthread_create() 来启动线程。我正计划做一些事情,比如添加一个静态成员变量,它只允许一个实例在任何给定时间与硬件通信。也就是说,我正在考虑允许调用者拥有该类的多个实例,但一次只能“连接”一个。这是标准做法,还是我的思维方式有一些“hacky”?在给定时间只会连接一个硬件,因此只需要在给定时间运行一个类实例。
感谢你的帮助。此外,如果您只是要建议“老兄,请使用 Boost 线程,FTW”之类的建议,请屏住呼吸。虽然我最终会转向线程库,但我的理解是 Boost 只是在 POSIX 系统上包装了 pthread。因此,我想在使用库宠坏自己之前先了解如何使用原始线程。虽然我的主要目标是按时交付,但没有人说我在此过程中学不到任何东西。;)
编辑添加:
为了清楚起见,这里有一些描述我看到的问题的源代码。在这种情况下,我仍然不能 100% 确定 extern "C" 正在做任何事情......
在我的 .h 中:
class MyClass
{
private:
static void* ThreadFunc(void* args); // extern "C" not found in declaration
static bool instance_;
};
在我的 .cpp 中:
MyClass::MyClass() {
if (!instance_) {
instance_ = true;
// spawn threads here
} else {
// don't spawn threads and warn user
}
}
extern "C" {
void *MyClass::ThreadFunc(void* args) { //definintion wrapped in extern C
MyClass* myclass_ptr = static_cast<MyClass*>(args);
// ... more code
return static_cast<void*> 0;
}