2014-10-21 3 views
-2

Как и в теме, у меня проблема с параллельным вызовом внешней программы на C++. Я подготовил код, показанный ниже, который использует system() для вызова моей программы, но он не является потокобезопасным, а результаты случайны - некоторые прогоны являются хорошими другими обратными ошибками. Есть ли другой возможный метод для параллельной работы в потоковом режиме? Пока я использую bat-файл с несколькими командами запуска и жду, когда все потоки возвращают выходные файлы, но это очень уродливое решение.Параллельный вызов внешней программы в C++

vector<thread> threadArray; 

    int nThread= 0; 

    // run calcs 

    for (int nThread = 0; nThread < quantity; nThread++) 
    { 
     threadArray.push_back(thread(system, ("start ccx.exe Calculix_wings_" + to_string(nThread)).c_str())); 
     threadArray.push_back(thread(system, ("start ccx.exe Calculix_fus_" + to_string(nThread)).c_str())); 
     cout << ("start ccx.exe Calculix_wings_" + to_string(nThread)).c_str() << endl; 
     cout << ("start ccx.exe Calculix_fus_" + to_string(nThread)).c_str() << endl; 
    } 

    for (auto it = threadArray.begin(); it != threadArray.end(); ++it) 
    { 
     it->join(); 
    } 

Я нашел несколько похожих тем, но ни один из них не был полезен.

Программа является структурным решателем напряжений Calculix. Вот вывод cmd:

start ccx.exe Calculix_wings_0 
start ccx.exe Calculix_fus_0 
start ccx.exe Calculix_wings_1 
start ccx.exe Calculix_fus_1 
start ccx.exe Calculix_wings_2 
start ccx.exe Calculix_fus_2 
start ccx.exe Calculix_wings_3 
start ccx.exe Calculix_fus_3 
start ccx.exe Calculix_wings_4 
start ccx.exe Calculix_fus_4 
start ccx.exe Calculix_wings_5 
start ccx.exe Calculix_fus_5 
'üÜ+' is not recognized as an internal or external command, 
operable program or batch file. 
'Čŕ+' is not recognized as an internal or external command, 
operable program or batch file. 
'-' is not recognized as an internal or external command, 
operable program or batch file. 
'c' is not recognized as an internal or external command, 
operable program or batch file. 
'l' is not recognized as an internal or external command, 
operable program or batch file. 
'o' is not recognized as an internal or external command, 
operable program or batch file. 
'x' is not recognized as an internal or external command, 
operable program or batch file. 
'îţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţî 
ţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţîţî 
ţîţîţîţîţîţîţîţîţ' is not recognized as an internal or external command, 
operable program or batch file. 
'-' is not recognized as an internal or external command, 
operable program or batch file. 
'l' is not recognized as an internal or external command, 
operable program or batch file. 

Должно возникнуть проблема с безопасностью потока, как вы можете видеть на выходе. В начале там строки с командой запуска - не исчерпывающие, а затем ошибки, связанные с системой() в параллельном запуске. В этом конкретном запуске только два вычисления завершены с успехом, а в конце «2». Hovewer это случайный, иногда выполняется 5 прогонов, иногда 3. Когда я создаю из первых строк файл bat, все в порядке. Я ожидаю запустить ccx.exe для каждого входа, а затем дождитесь, пока все потоки завершат вычисления, чтобы продолжить обработку выходных файлов постобработки.

+1

Какие ошибки вы получаете? Какую программу вы вызываете, чтобы сделать ее небезопасной? Код, который вы показываете здесь, ничего не делает, что может быть опасным. –

+0

Вам нужно будет предоставить более подробную информацию. Какие ошибки? Какое поведение вы ожидали? – dohashi

+0

Для [system] (http://www.cplusplus.com/reference/cstdlib/system/) он говорит: «Функция обращается к массиву, указанному командой. Одновременно вызов этой функции с нулевым указателем в качестве аргумента безопасен. , это зависит от реализации системы и библиотеки ». Возможно, это ваша проблема. – crashmstr

ответ

0

Выражение ("start ccx.exe Calculix_wings_" + to_string(nThread)) создает объект временныйstd::string, и так как вы затем использовать c_str, чтобы получить указатель, то thread constructorтолько копирует указатель на этот временный объект. Как только конструктор возвращается, временный объект разрушается, а поток остается с висящим указателем.

Использование оборванных (или иначе незаконных) указателей приводит к undefined behavior, что и есть то, что вы видите.

Невозможно решить эту проблему напрямую, вам нужно использовать функцию-обертку, которая принимает объект std::string как аргумент, и пусть конструктор потока копирует временный объект строки. Для этого вы можете использовать лямбда:

threadArray.push_back(thread(
    [](const std::string arg) { system(arg.c_str()); }, 
    ("start ccx.exe Calculix_wings_" + to_string(nThread)))); 

Или не передать аргумент вообще:

threadArray.push_back(thread(
    [nThread]() 
    { 
     system(("start ccx.exe Calculix_wings_" + to_string(nThread))); 
    })); 
+0

Спасибо большое! Я использовал второй код с дополнительным c_str(). Теперь он работает нормально. – curky

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