【问题标题】:Calling a function when thread is exiting in PThreads or Windows当线程在 PThreads 或 Windows 中退出时调用函数
【发布时间】:2012-05-10 13:39:32
【问题描述】:

我正在为 Linux(带有 PThreads)和 Windows(带有内置 WinThreads)创建一个 C++ 库,它可以附加到任何程序,并且需要在线程退出时调用一个函数,类似于如何atexit 适用于进程。

我知道 pthreads 的 pthread_cleanup_push 和 pthread_cleanup_pop,但它们对我不起作用,因为它们是添加另一个词法范围的宏,而我想在第一次调用我的库时声明这个函数,然后允许程序自己运行自己的代码,但它需要。我在 Windows 中没有发现任何类似的东西。

请注意,这并不意味着我希望在线程停止时提醒外部线程,或者甚至我可以更改线程退出的方式,因为这是由程序本身控制的,我的库只是随车附上。

所以问题是:在这种情况下,当我无法控制如何在 Windows 或 Linux 中关闭线程时调用我编写的函数时,最好的方法是什么?线程是创建还是销毁?

例如在主程序中:

void* threadFunc(void* arg)
{
    printf("Hello world!\n");
    return NULL;
}

int main(int argc, char** argv)
{
    int        numThreads = 1;
    pid_t*     pids       = NULL;
    pids     = (pid_t*)     calloc(sizeof(pid_t), numThreads);

    pthread_create(&ntid, NULL, threadFunc, &nVal);
    pthreads[0] = ntid;

    pthread_join(pthreads[0], NULL);
    return 0;
}

在图书馆:

void callMeOnExit()
{
    printf("Exiting Thread!\n");
}

我希望在线程达到 return NULL 时调用 callMeOnExit;在这种情况下,以及当主线程到达时返回 0;。包装 pthread_exit 将适用于其他情况,并且可能是一种解决方案,但如果可能的话,我想要一个更好的解决方案。

如果有人对我如何能够做到这一点有任何想法,那就太好了!

【问题讨论】:

  • 您正在创建一个 C++ 库?好吧,不要粗鲁,但如果你问的是这种性质的东西,而不是严格阅读相关规范,那么也许你应该只使用 boost 或 qt。已经有库可以满足您的需求。一个人的图书馆就像一个人的船员一样现实——如果你要提供你正在谈论的功能,那么大量的工作是不可能的。如果你为这个特定的工作写了一个包装类而不是一个库,这听起来很适用。
  • 但是,为了获得答案,或者可能是为了了解您想要做什么:包装类可以隐藏复杂性并管理线程的创建和启动,并且与平台无关。我确信有某种方法可以让包装类在启动之前调用你想要的函数,并在它退出时再次/另一个函数。
  • 发送到 DLL 的 Dllmain() 函数的 Windows DLL_THREAD_DETACH 消息可能会有所帮助,但我认为也有很多可能的陷阱。
  • @Adam Miller:这不是特别有用,除非您将您的评论归结为“我建议您包装 boost 或 qt 线程来实现此功能”的内容
  • @Adam:我认为问题不在于包装线程 API 的库 - 我相信有问题的库不参与线程的创建(但这还不清楚 - 它如果是这样的话,可能应该说清楚)。

标签: c++ windows linux multithreading pthreads


【解决方案1】:

因此,经过几次代码审查后,我们能够在 Linux 中找到一种更优雅的方式来执行此操作,它既符合 Windows 对 Fibers 所做的(正如 Neeraj 指出的那样),也符合我在开始研究这个问题。

关键是pthread_key_create 接收作为第二个参数的指向析构函数的指针,当任何已初始化此 TLS 数据的线程死亡时调用该析构函数。我已经在每个线程的其他地方使用了 TLS,但是一个简单的存储到 TLS 中也可以获得这个功能,以确保它被调用。

【讨论】:

  • 正是我想要的!这很有意义,因为当人们想到“线程清理例程”时,清理 TLS 数据通常是首先要做的事情。
【解决方案2】:

对于 Windows,您可以尝试Fls Callbacks。它们的 FLS 系统可用于为每个线程分配(忽略“光纤”部分,每个线程包含一根光纤)存储。您可以通过此回调释放存储空间,但也可以在回调中执行其他操作。

【讨论】:

  • FLS 回调对此很有效,但有一点需要注意。如果 FLS 插槽在使用它的最后一个线程退出之前被释放,那么您将立即为每个已使用 FLS 索引且仍处于活动状态的线程获得回调,并且此回调发生在释放 FLS 索引的线程上。所以,只要你的索引比你跟踪的所有线程都长,你就可以了,当它退出时你会在线程上得到一个回调。
【解决方案3】:

改变这个:

pthread_create(&ntid, NULL, threadFunc, &nVal);

进入:

struct exitInformData
{
   void* (CB*)(void*);
   void* data;
   exitInformData(void* (cp*)(void*), void* dp): CB(cp) data(dp) {}
};
pthread_create(&ntid, NULL, exitInform, new exitInformData(&threadFunc, &nVal));

然后添加:

void* exitInform(void* data)
{
    exitInformData* ei = reinterpret_cast<exitInformData*>(data);

    void* r = (ei.CB)(ei.data);   // Calls the function you want.
    callMeOnExit();               // Calls the exit notification.
    delete ei;
    return r;
}

【讨论】:

  • 这几乎是我使用的。我实际上有一个线程对象和一个线程运行器。跑步者有一个虚函数run(),这是用户编写代码的地方。调用run()函数的函数可以根据需要准备和清理线程。
  • @AlexisWilke:这个建议已经有 4 年历史了。新版本的 C++ 有一个线程对象std::thread 为您处理所有这些。查看en.cppreference.com/w/cpp/thread/thread
  • 是的,更改旧代码需要时间...我在 5 或 6 年前写过类似的东西...没有 C++11(或 14 或 17...)
【解决方案4】:

我发现this已经被问过了,虽然当时给出的解决方案可能和你想要的不一样...

另一个想法可能是简单地从 pthread_t 类/结构扩展,并覆盖 pthread_exit 调用以根据需要调用另一个函数,然后调用超类 pthread_exit

【讨论】:

  • 该链接似乎假设有一个外部线程需要在程序结束时得到通知,而不是程序本身。这不是一个真正的选择,所以我不确定它是否有帮助(尽管它表明没有人提到任何其他像我正在寻找的东西)。我假设 pthread 对象类是 final/const,不是这样吗?如果没有,那可能是要走的路,然后在我完成工作后调用 pthread_exit 函数。
  • 是的,对链接感到抱歉,我没有完整阅读它,但我认为它可能会有所帮助,因为您可能会根据自己的需要调整它,但我想不会。如果 pthread_t 不是一个对象,那么我会感到惊讶,我习惯于将一切都视为一个对象。不过我很确定,pthread 可能不是对象,在这种情况下,我之前讨论的解决方案将适用。
  • 我认为 pthread_t 的内容(我一直认为它是一个结构,因为它可以在 C 和 C++ 中使用)依赖于实现并且是封闭的,但我们可以重新定义 pthread_exit使用一些不错的#define 魔法,然后在我完成代码后直接调用真正的 pthread_exit,这样我们就不必担心 pthread_t 的实际内容,并且可以为 Windows 执行类似的方法。
  • 结构很像类:见the selected answer here-它们可以被继承。另外,您可以在 pthread_t 对象上调用 new ,因此创建子类似乎是最有效的方法......尽管 Idk 如果重写 pthread_exit 函数将是一个痛苦的 patoot 或不是 - 它被声明为虚拟的吗?这有关系吗?
  • 尝试和扩展总是值得的,唯一会发生的就是你得到一个编译器错误,并且必须以另一种方式来做,这听起来要困难得多。
猜你喜欢
  • 1970-01-01
  • 2019-09-10
  • 2021-11-25
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 2012-10-24
  • 2011-06-02
相关资源
最近更新 更多