2014-11-19 2 views
1

У меня есть функция C++ 11, вызывающая вызовы против унаследованной функции C. Я подумал, что было бы хорошо создать рабочие потоки (используя std::thread, который затем передаст переменные функции C. Однако, казалось бы, если поток слишком долго ждет выполнения, то указатели тогда больше не указывают на допустимые места в памяти .Почему значения необработанных указателей перезаписываются/выпадают из области?

Пример (замкнуто для краткости/читаемости, и, очевидно, не код продукции, но воссоздает вопрос):.

//The C function 
void c_func(const char* str1, const char* str2, const char* str3){ 

    printf("My strings str1: %s, str2: %s, str3: %s\n", str1, str2, str3); 
} 

... 

//C++ calling the function from numerous threads 
std::vector<std::thread> threads; 
std::vector<std::vector<std::string>> bar; 
... 
for (auto const& foo : bar) 
    { 
     threads.push_back(std::thread(c_func, foo[0].c_str(), foo[1].c_str(), (foo[0] + foo[1]).c_str())); 
    } 

в распечатке будет распечатай мусор в разные случайные моменты времени После некоторого экспериментирования, я заметил, что это делает не происходит, когда я изменяю функцию «C», чтобы использовать std::string вместо const char*. Однако это изменение означало бы тонну перезаписи на наследство код ... который я бы предпочел не делать ...

Есть ли способ разрешить этот тип многопоточного вызова без указателей, указывающих на мусор, если поток не выполняется вовремя? Или я застрял с переписыванием устаревшего кода, чтобы переместить его на C++ ...

+4

Вы выдаете указатели, которые действительны только для времени жизни 'std :: string', из которого они пришли, а затем весело продолжайте делать то, что вы делали в этом потоке, предположительно отбрасывая некоторые из этих 'std: : string's по пути. Это принципиально нарушено, никоим образом не вокруг. На самом деле это не совсем так, как хранить 'char *' в обычной структуре данных, отбрасывая '' '' '' '' '' '' '' '', а затем выбирая 'char *' s, откуда вы их сохранили. Объедините свои жизни вместе. – delnan

+0

@ delnan Gotcha, спасибо за вклад ... Это то, что я подозревал, но не хотел в это верить. –

+2

он сломан даже без потоковой передачи, '(foo [0] + foo [1]). C_str();' будет возвращать мусор, потому что временная строка будет уничтожена после полной оценки выражения. –

ответ

7

Поскольку c_str() не предотвращает очистку строки. После того, как функция возвращает и стержень очищается, строки foo также очищаются, что может быть до начала потока.

Вы должны пройти фактический std::string (возможно, в оболочку, а затем извлечь char* перед вызовом func) или иным образом обеспечить строки не очищаются, прежде чем вы join() эд всех нитей.

+0

Эта идея обертки сразу пришла мне в голову. Лучшее из обоих миров, не переписывая старый код, но все же способный гарантировать жизнь указателя в течение всего потока. –

7

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

Что вам нужно сделать, так это пройти std::string в каждой теме. Не ссылка, не указатель, а копия. Теперь каждому потоку принадлежит собственная копия строки, которая будет автоматически очищена с помощью магии стека и деструкторов.

Теперь вы можете позвонить c_str() на каждую строчную копию, чтобы получить указатель, который будет действителен для этого потока и не будет очищен в другой области.

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