2009-05-15 3 views
0

Я пытаюсь вызвать функцию «Запуск» в новом потоке. Прямо сейчас у меня есть этот код с использованием openMP, который фактически не запускает «Run» в новом потоке. ПРИМЕЧАНИЕ. Я не прошу помощи с помощью OpenMP. Этот код был просто быстрым решением. Я бы предпочел использовать метод CreateThread().Многопоточность с наследованием (C++)

vector<ICommand*>* commands; 
string strInput; 
// For each command... 
for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i) 
{ 
    // ...if the current command we're examining is valid... 
    if((*i)->ContainsCommand(strInput)) 
    { 
     // ...run it in a new thread and don't let ZChatInput handle it normally... 
     #pragma omp sections nowait 
     { 
     #pragma omp section 
      (*i)->Run(strInput); 
     #pragma omp section 
      bRet = false; 
     } 

     // ...and don't check any more commands. 
     break; 
    } 

} 

Так как это можно сделать, используя только стандарт и STL? Конечно, я ищу способ, который работает :)

ответ

0

Итак, я понял это после двойной проверки документации MSDN. Вот как я это сделал, в случае, если кто-то из вас интересует:

static vector<ICommand*>* commands; 
// This is what we pass to CommandOnThread. 
struct CommandParameter 
{ 
    string strInput; 
    ICommand* command; 
}; 

int CommandOnThread(CommandParameter* cp) 
{ 
    cp->command->Run(cp->strInput); 
    delete cp; 

    return 0; 
} 

void foo() 
{ 
    string strInput; 
    ... 
    // For each command... 
    for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i) 
    { 
     // ...if the current command we're examining is valid... 
     if((*i)->ContainsCommand(strInput)) 
     { 
      // Put the CP on the stack. 
      CommandParameter* temp = new CommandParameter; 
      if(temp == NULL) 
      { 
       Print("Out of memory!"); 
       bRet = false; 
       break; 
      } 

      // ...set up the parameters to createthread... 
      temp->strInput = strInput; 
      temp->command = *i; 

      // ...run it in a new thread... 
      CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)CommandOnThread, temp, NULL, NULL); 

      // ...and don't check any more commands. 
      bRet = false; 
      break; 
     } 
    } 
} 
3

Как насчет использования Boost.Thread?

if((*i)->ContainsCommand(strInput)) 
{ 
    boost::thread t(boost::bind(&ICommand::Run, *i)); 
} 

Это запустит «Запуск» в отдельной ветке. (Заметьте, я не тестировал это.)

+0

Нет, извините. Я пытаюсь уклониться от сторонних библиотек. Если эта функция находится в VS2010, я попробую ее; но до сих пор все еще не то, что я ищу. Кроме того, вы забыли передать strInput в качестве параметра. –

+2

В чем проблема с boost? Это почти стандарт, как stl. Многие новые библиотеки ускоряются в новом стандарте, и я не буду впечатлен, если новые потоки станут новым стандартом (я знаю, что существует новый стандарт для потоков, но я не знаю, похожи ли они на увеличение потока модель) –

+0

C++ 0x будет иметь потоковые объекты, которые напоминают boost.thread. См. Http://en.wikipedia.org/wiki/C%2B%2B0x#Threading_facilities –

1

Вы действительно хотите создать поток для каждой команды? Создание темы дорого. Если вам абсолютно необходимо, чтобы эта часть была асинхронной - создайте синхронизированную очередь, укажите число потоков (это ваша масштабируемость здесь), заставьте их блокировать очередь, затем поместите сообщение (указатель?) В очередь в вашем цикле ,

Отвечая на Ваш комментарий:

 
// setup 
sync_queue wq; // that would be protected by mutex and a conditional var or two 
for (i = 0; i < parallel_factor; ++i) start_thread(th_func, wq); 
... 

// your loop body : 
    ... 
    if (valid_input) q.put(item); 
    ... 

// thread function 
void th_func(sync_queue& q) 
{ 
    work_item* pwi; 
    while ((pwi = q.get())) do_it(pwi); 
} 

имеет смысл?

+0

Это НЕ создает поток для каждой команды. Это только создание потока, если вход действителен и не более. Он ДОЛЖЕН быть асинхронным, так как в противном случае это становится очень мучительно медленным. Я не понимаю вашу стратегию реализации. Можете ли вы показать какой-то пример псевдокода? –

+0

Он делает ... но это похоже на большую работу для простого создания потоков ... Там должен быть лучший способ с CreateThread или другим WinAPI. –

+0

Вы вызываете Run() для каждого допустимого ввода? Затем запустите поток (ы). В противном случае вы можете обнаружить, что он медленнее, чем однопоточный. И, да, возиться с потоками - это много работы. –

2
+0

Можете ли вы показать мне в контексте кода, который я поставил? –

+0

, аналогичный примеру boost, вы используете указатель на свою функцию в качестве параметра и вверх. _beginthread и CreateThread - это функции MS для многопоточности. – DaClown

+0

int h = (HANDLE) _beginthreadex (NULL, 0, (* i) -> Run, & strInput, 0, NULL); не совсем уверен, и Run должен быть функцией _stdcall. Это win32 api – ryansstack

2

Вы можете попробовать что-то вроде этого:

vector<ICommand*>* commands; 
string strInput; 

void CommandOnThread(void* command) 
{ 
    (ICommand*)command->Run(); 
} 

// For each command... 
for(vector<ICommand*>::iterator i = commands->begin(); i != commands->end(); ++i) 
{ 
    // ...if the current command we're examining is valid... 
    if((*i)->ContainsCommand(strInput)) 
    { 
     //Attach the input to the command 
     (*i)->AttachInput(strInput); 
     _beginthread(CommandOnThread, 0, *i); 
     break; 
    } 
} 

Для этого нужно изменить интерфейс командной немного для прохождения ввода команд в два этапа: первый сохранить введенные в объекте управления и затем вызвать Выполнить() без аргументов. Вы можете заменить _beginthread на CreateThread, если вам нравится, что они очень похожи.

Просто пояснить: нельзя использовать метод экземпляра в качестве параметра функции для _beginthread (или CreateThread). Решение выше - передать объект (команду) функции, а затем вызвать его метод экземпляра (Run). Однако в этом случае вы не можете передавать дополнительные аргументы функции потока и, следовательно, не можете передавать аргументы методу экземпляра. Самое простое решение для этого - как-то присоединить аргумент к экземпляру, прежде чем передать его функции потока.

Надеюсь, это поможет. Конечно, это решение невозможно, если вы не можете изменить интерфейс и реализацию класса Command.

+0

Где именно находится "AttachInput"? Кроме того, вы не передаете какие-либо параметры команде-> Выполнить() –

+0

Вы должны определить это самостоятельно. Вы можете передать только один аргумент функции потока, и он уже используется для передачи объекта команды. –

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