【问题标题】:Asynchronous function call for C++C++ 的异步函数调用
【发布时间】:2010-08-02 16:35:03
【问题描述】:

我需要提示如何在 C/C++ 中实现异步函数调用(或 windows 和/或 linux 的框架名称/API 调用)

用例如下:父线程调用函数。该函数创建一个子线程并返回,因此调用是非阻塞的,父线程可以继续做一些工作。

例如 pthread_join 不适合获取结果,因此必须将结果存储在堆中,并且必须通知父级。我想要的是类似于父线程中的回调函数,它将在子线程准备好工作后执行。

这很令人惊讶,但我在谷歌中找不到一个例子。

感谢您的帮助

【问题讨论】:

  • 只是为了让我们得到一个参考,您使用什么语言/框架来建模您的问题。你似乎有一些非常具体的想法。如果您可以提供参考,那么有人可能知道 C++ 的等效框架。但正如下面所回答的,基本构建块将是 boost::threads,尽管与您想要的相比,这是非常低的级别。
  • 哪个,C 还是 C++??下定决心!

标签: c++ c asynchronous


【解决方案1】:

C++0x 为此提供了std::async。这是现有的 implementationdiscussionWikipedia

【讨论】:

    【解决方案2】:

    而不是使用不同的框架,并注意到您在问题中提到了pthread_join(),您仍然可以使用 POSIX C 实现所需的效果。为此,您可以使用信号来确认并行任务完成的线程.在此方法中,您为用户定义的信号(例如SIGUSR1)安装信号处理程序,创建一组具有不同任务的工作线程,并让它们在完成时向父级发出信号。

    以下程序说明了这种尝试。在示例中,我使用SIGUSR1 通知父线程某些处理完成。父线程一直忙于做一些 I/O,直到被子线程中断。请注意,为清楚起见,没有放置任何类型的错误处理代码。

    #include <pthread.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    /* Variable to hold the value of some calculation. */
    int value = 0;
    
    /* Variable used by the parent thread to inform itself of task completion. */
    volatile sig_atomic_t value_received = 0;
    
    /* Signal handler to handle the SIGUSR1 signal (the signal used to acknowledge the parent of task completion). */
    void handler(int signum) {
        value_received = 1;
    }
    
    /* Working thread routine. First parameter is a pthread_t (cast to void*) identifying the parent. */
    void *thread(void *parent) {
        /* Do something lengthy here, such as a long calculation. */
        value = 1;
        sleep(5); /* Simulate lengthy operation. */
    
        /* After processing, inform the parent thread that we have ended. */
        pthread_kill((pthread_t)parent, SIGUSR1);
        return NULL;
    }
    
    int main(void) {
        struct sigaction action;
        pthread_t child;
    
        /* Install signal handler to receive the child thread notification. */
        action.sa_handler = handler;
        sigemptyset(&action.sa_mask);
        action.sa_flags = 0;
        sigaction(SIGUSR1, &action, NULL);
    
        /* Create child thread that will perform some task. */
        pthread_create(&child, NULL, thread, (void*)pthread_self());
    
        /* Detach thread from execution. No need to join the thread later. */
        pthread_detach(child);
    
        /* Do some other processing while the ongoing task is running in parallel. */
        while (!value_received) {
            char buffer[0x100];
    
            /* Echo some input until something happens. */
            if (!fgets(buffer, sizeof buffer, stdin))
                break;
            printf("You typed: %s", buffer);
        }
    
        /* Something happened (signal received or EOF in stdin). In the latter, just sleep a little while. */
        if (feof(stdin))
            while (!value_received)
                sleep(1);
    
        /* At this point, child thread has already ended the execution. */
        printf("Value received: %i\n", value);
        return EXIT_SUCCESS;
    }
    

    该示例使用信号的 LinuxThreads 实现,这与 POSIX 定义的完全不同。如果您担心可移植性或合规性,则应进一步修改上述解决方案。

    【讨论】:

    • 这是标准,它是 C,但它不是标准 C。(sigaction、pthreads 等是 POSIX 或 SUS 标准的一部分,而不是 ANSI C 标准)
    • @BenVoigt 你是对的。但是,我倾向于认为大多数 C 和 C++ 程序员可能倾向于使用 Linux,并且默认情况下,大多数主要的 Linux 发行版都带有 POSIX。如果我错了,请纠正我。
    • @热心geek:你错了。 Linux 的 C 和 C++ 市场份额很小。特别是对于 C,大多数平台都太小而无法运行 Linux。对于桌面应用程序,大多数程序员都希望它也能在 Windows 上工作,即使他们使用 Linux 进行开发。但即使在开发者社区,Windows 也比 Linux 拥有更多的市场份额(当然比用户之间的差距要小得多)。
    • 但实际上,即使您的评论是正确的,错误地编写“标准 C”仍然没有任何好处。
    • @BenVoigt 我明白了。可能是因为我只在 Linux(嵌入式和服务器)上使用 C++,而且我办公室里的大多数人都是如此。但同样,我们的前端都是 Windows 和 Java。我也没有注意到他之前写的“标准 C”(强调 - 标准)评论。
    【解决方案3】:

    【讨论】:

      【解决方案4】:

      Boost.Thread

      我相信这可以很好地完成工作。将函数调用作为一个新线程启动,而不必费心加入它。无论如何,我相信它会在它完成时解决这个问题。

      您可以进行设置,以便子级在完成使用Boost.Signals 时向父级发送信号。此信号将链接到父级的回调函数。

      【讨论】:

      • 我已经看过 boost-signals ,但它似乎不是我想要的。我还没有尝试过,但我似乎将在当前(在我的情况下为子)线程的上下文中执行“插槽”功能。如果我错了,请纠正我
      • 误解了这个问题。 Boost.Thread 确实是您想要的。编辑我的答案。
      【解决方案5】:

      使用 boost::thread 作为标准的跨平台解决方案。如果您需要更多相关内容,可以使用英特尔的线程构建模块。

      【讨论】:

      • 我看过文档,似乎 boost 没有提供这样的实现。不可能为线程或未来对象提供“回调”函数。有 set_wait_callback 但只有在未来对象准备好时才会调用它
      【解决方案6】:

      您必须设置某种基础架构来通知调用者工作已完成。这可以通过观察者模式类型来完成。也可以使用消息类型基础架构。

      真正的问题是你的父母在等待的时候会做什么。你想让它轮询结果吗?或者得到通知?

      【讨论】:

      • 父线程可以例如处理 GUI 的消息循环。我想得到通知 - 这总是可以给函数一个指向缓冲区的指针,结果将存储在该缓冲区中,并且由于线程在同一个进程中,因此可以在“回调”函数中轻松读取结果
      【解决方案7】:

      使用 Qt 框架和 Thread 类或 Qt Concurrency 框架。

      连接到 QThread::finished() 或 QFutureWatcher::finished() 信号以在工作完成时得到通知。

      【讨论】:

      • 虽然我完全支持 Qt,否则我会选择 TBB 或类似的东西。
      【解决方案8】:

      我在您对 Starkey 的回复中看到,主线程是 UI 线程。

      我使用了几种不同的 GUI 工具包,它们都允许您从不同的线程发布消息。所以让工作线程在完成后发布一条 GUI 消息,然后处理程序将在主线程中运行。

      在 Windows 中,使用 PostMessage

      在 Linux 中,使用 XtAppAddSignal and XtNoticeSignal

      【讨论】:

        猜你喜欢
        • 2012-07-25
        • 2012-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-20
        • 2022-01-02
        • 2013-03-28
        相关资源
        最近更新 更多