2010-08-02 6 views
6

C++ Мне нужна подсказка, как реализовать асинхронные вызовы функций в C/C++ (или имена рамок/API вызовов для окон и/или Linux)вызова функции асинхронной для

Прецедент имеет следующий вид: Родитель резьба вызывает функцию. Функция создает дочерний поток и возвращает, поэтому вызов неблокируется, а родительский поток может продолжать выполнять некоторую работу.

Например, pthread_join для получения результата не подходит, поэтому результат должен быть сохранен в куче, а родитель должен быть уведомлен. Я хочу что-то вроде функции обратного вызова в родительском потоке, которая будет выполняться после того, как дочерний поток будет готов с заданием.

Это удивительно, но я не могу найти ни одного примера в Google.

Спасибо за помощь

+0

Только таким образом мы получаем ссылку на то, что язык/рамки вы моделирования на ваш вопрос на. У вас, кажется, есть что-то очень специфическое в виду. Если бы вы могли предоставить ссылку, кто-то может знать эквивалентную структуру для C++. Но, как было сказано ниже, базовый строительный блок будет boost :: threads, хотя это очень низкий уровень по сравнению с тем, что вы хотите. –

+12

Какой, C или C++ ?? Придумайте людей! –

ответ

3

Boost.Thread

Я считаю, что это делает работу хорошо. Выделите вызов функции как новый поток и просто не мешайте ему присоединяться. По-моему, это позаботится об этом, когда все закончится.

Вы можете настроить его так, чтобы ребенок посылал сигнал родительскому лицу, когда он заканчивает использование Boost.Signals. Этот сигнал будет связан с функцией обратного вызова родителя.

+0

Я уже смотрел сигналы форсирования, и, похоже, это не то, что я хочу. Я еще не пробовал, но мне кажется, что «слот» -функция будет выполняться в контексте текущего (в моем случае дочернего) потока. Пожалуйста, поправьте меня, если я ошибаюсь – iddqd

+0

Непонятно. Boost.Thread - это то, что вы хотите. Редактирование моего ответа. –

1

Используйте boost :: thread как стандартное кросс-платформенное решение. Если вам нужно что-то более активное, есть блоки потоковой сборки Intel.

+0

Я посмотрел документы, и кажется, что boost не обеспечивает такую ​​реализацию. Невозможно обеспечить функцию «обратного вызова» для потока или будущего объекта. Существует set_wait_callback, но он вызывается только в том случае, если будущий объект * не * готов – iddqd

0

Вам нужно будет настроить инфраструктуру, чтобы уведомить вызывающего, что работа выполнена. Это можно сделать с помощью типа шаблона Observer. Также может использоваться инфраструктура типа сообщения.

Реальный вопрос - что ваш родитель собирается делать, пока он ждет. Вы хотите, чтобы он опросил результаты? Или получить уведомление?

+0

. Родительский поток может, например, обрабатывать цикл сообщений для графического интерфейса. Я хочу получить уведомление - это всегда можно дать функции указатель на буфер, где будет храниться результат, и поскольку потоки находятся в одном процессе, результат может быть легко прочитан в функции «обратного вызова» – iddqd

0

Используйте рамки Qt и классы Thread или рамки Qt Concurrency.

Подключитесь к сигналу QThread :: finished() или QFutureWatcher :: finished(), чтобы получать уведомление, когда работа выполнена.

+2

Qt is ew ... ................ –

+0

@Matt и где это решение не Qt ... – TimW

+0

Пока я все для Qt, здесь я бы пошел с TBB или что-то в этом роде , –

7

Вместо того, чтобы использовать разные фреймворки и отмечая, что вы упомянули pthread_join() в своем вопросе, вы все равно можете добиться желаемого эффекта с помощью POSIX C. Для этого вы можете использовать сигналы для подтверждения потока параллельной задачи. В этом методе вы устанавливаете обработчик сигнала для определяемого пользователем сигнала (например, SIGUSR1), создайте набор рабочих потоков с различными задачами и дайте им возможность сигнализировать родителям, когда они будут завершены.

Следующая программа иллюстрирует попытку. В этом примере я использую SIGUSR1, чтобы сообщить родительскому потоку о завершении некоторой обработки. Родительский поток остается занятым, делая некоторые операции ввода-вывода, пока не будет прерван дочерним потоком. Обратите внимание, что для ясности код ошибки не обрабатывается.

#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. Если вы заинтересованы в переносимости или соблюдении, вышеуказанное решение следует дополнительно пересмотреть.

+1

Это стандарт, и это C, но он не является стандартным C. (sigaction, pthreads и т. Д. Являются частью стандартов POSIX или SUS, а не стандарта ANSI C) –

+0

@BenVoigt верный. Тем не менее, я бы склонен думать, что большинство программистов на C и C++ могут склоняться к использованию Linux и по умолчанию большинство основных Linux Distros поставляются с POSIX. Пожалуйста, поправьте меня, если я ошибаюсь. – enthusiasticgeek

+0

@enthusiasticgeek: Вы ошибаетесь. Linux имеет довольно небольшую долю на рынке C и C++. Для C особенно большинство платформ слишком малы для запуска Linux. А для настольных приложений у большинства программистов есть желание, чтобы он также работал на Windows, даже если они развиваются с использованием Linux. Но даже в сообществах разработчиков Windows имеет больше доли рынка, чем Linux (разница, конечно, намного меньше, чем среди пользователей). –

0

Я вижу в вашем ответе Старки, что основной поток представляет собой поток пользовательского интерфейса.

Я использовал несколько различных инструментальных средств GUI, и все они позволяют отправлять сообщения из другого потока. Поэтому, когда рабочий поток отправляет сообщение GUI, когда оно будет завершено, обработчик будет запускаться в основном потоке.

В Windows используйте PostMessage.

В Linux, используйте XtAppAddSignal and XtNoticeSignal

Смежные вопросы