2013-11-13 3 views
1

Я пишу программное обеспечение на C/C++, используя библиотеку интервальных алгебр BIAS/Profil. В моем алгоритме у меня есть мастер, который делит домен и передает его части в подчиненный процесс. Те возвращают int закон об этих доменах. Есть общие данные для чтения, и все.memcpy [или нет?] И многопоточность [std :: thread from C++ 11]

Мне нужно распараллелить мой код, однако, как только 2 подчиненных потока работают (или, более того, я думаю), и оба вызывающие функции этой библиотеки, это segfaults. Что характерно для этих segfaults, заключается в том, что gdb редко указывает одну и ту же линию ошибок из двух сборок: она зависит от скорости потоков, если она была запущена раньше и т. Д. Я попытался получить поток, пока не появится мастер, он «стабилизирует» ошибку. Я уверен, что это происходит из вызовов в memcpy библиотеки (после backtrace gdb, я всегда оказываюсь в функции BIAS/Profil, вызывающей memcpy. Чтобы быть справедливым, почти все функции называют memcpy временным объект перед возвратом результата ...). Из того, что я читал в Интернете, казалось бы, что memcpy() не может быть потокобезопасным, в зависимости от реализаций (особенно here). (Кажется странным, что функция должна читать только общие данные ... или, может быть, при написании потоков данных оба потока идут на одно и то же пространство памяти?)

Чтобы попытаться решить эту проблему, я бы хотел для «замены» (по крайней мере, для тестов, если изменения поведения) вызов memcpy для вызова с мьютексом. (что-то вроде mtx.lock(); mempcy (...); mtx.unlock();)

1-й вопрос: я вообще не разработчик dev/code и нехватка базовых знаний. Я думаю, что, когда я использую предварительно созданную библиотеку BIAS/Profil, memcpy называется одной из систем, на которой была построена библиотека, правильно? Если это так, изменилось бы это, если бы я попытался создать библиотеку из источника в моей системе? (Я не уверен, что может построить эту библиотеку, следовательно, вопрос.)

второго вопроса: в моем string.h, тетср объявлен: #ifndef __HAVE_ARCH_MEMCPY extern void * memcpy(void *,const void *,__kernel_size_t);#endif и в некоторых других струнных заголовках (string_64.h , string_32.h) определение формы: #define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len)) или еще более четкое определение или просто объявление, подобное цитируемому. Он начинает казаться уродливым, но, в идеале, я хотел бы создать препроцессорную переменную #define __HAVE_ARCH_MEMCPY 1 и void * memcpy(void *,const void *,__kernel_size_t), которая будет делать memcpy с мьютекс-рамкой с утерянной memcpy. Идея здесь состоит в том, чтобы избежать возиться с библиотекой и заставить ее работать с 3 строками кода;)

Любая идея? (Это сделало бы мой день ...)

+1

C/C++ не существует. Ваша тегировка с C, но ваш заголовок ссылается на C++ –

+0

@Jens: он мог писать на C++ и вызывать функцию C из своих файлов на C++. – Jimbo

ответ

1

Учитывая, что ваши наблюдения и что Profil lib находится в прошлом тысячелетии и что документация (домашняя страница и) даже не содержит слова «поток», я бы предположил, что lib не является потокобезопасным.

1-й: Нет, обычно memcpy является частью libc, которая динамически связана (по крайней мере, в наши дни). На linux проверьте с ldd NAMEOFBINARY, который должен дать строку с чем-то вроде libc.so.6 => /lib/i386-linux-gnu/libc.so.6 или аналогичным. Если нет: перестройте. Если да: восстановление может помочь в любом случае, так как есть много других факторов.

Кроме этого, я думаю, что memcpy является потокобезопасным до тех пор, пока вы никогда не записываете данные (даже если запись не измененных данных повредит: https://blogs.oracle.com/dave/entry/memcpy_concurrency_curiosities).

2nd: Если выясняется, что вы должны использовать модифицированный memcpy, также подумайте о LD_PRELOAD.

+0

Соглашаясь с вами в старости Profil, но не по моему выбору. и они сделали x64 версию ~ 3 года назад, может быть, поточно-безопасную через 10 лет?;)) 1 => 'ldd libBias.a' отвечает' не динамический исполняемый файл'. То же самое для других libs, поэтому я собираюсь попробовать перестроить. Memcpy должен читать только глобальные данные и писать локальные ... Я нашел ссылку, которую вы цитируете (и цитировал сам;)), и он говорит, что даже при чтении memcpy делали странные вещи. 2 => Я не знал об этом, спасибо большое. допустим, последнее ... Спасибо, ребята, за вашу реактивность! – luneart

+0

Окончание '.a'' libBias.a' говорит о том, что lib статически связан. Таким образом, «memcpy» - это тот, с которого и когда была встроена библиотека и встроена в нее. В этом случае вы должны перестроить. 'LD_PRELOAD' не работает в этом случае. –

+0

Извините, это неправильно. Тем не менее 'memcpy' не содержится и будет связан, когда вы создадите свою окончательную программу. (Чтобы подтвердить это: нет 'memcpy.o', если вы делаете' ar t libBias.a'.) –

0

В общем, вы должны использовать critical section, mutex или какой-либо другой метод защиты, чтобы держать несколько потоков от доступа не Потокобезопасный (не- Реентрантного) функции одновременно. Некоторые реализации ANSI C от memcpy() не являются потокобезопасными, некоторые из них. (safe, not safe)

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

+0

Я использую мьютексы, но я не могу войти в какую-то библиотеку и начинать помещать мьютексы повсюду. То, что я могу сделать в теории, - это помещать мьютексы каждый раз, когда я использую функцию из библиотеки, но, учитывая, что я использую ее много, в значительной степени это будет делать это последовательно. Спасибо в любом случае за ваш ответ и реактивность! – luneart

+0

Я не предлагаю изменить библиотеку. Тем не менее, важно защитить любую небезобезопасную функцию, которая используется из одной из этих библиотек, например, некоторые реализации memcpy() (или любой функции, вызывающей функцию без повторного входа), используя один о тех методах, о которых я говорил выше. Токены или переменные, зависящие от потока, также являются опциями. (Вы не изменяете библиотеку, чтобы делать эти вещи, скорее они выполняются в приложении, которое вызывает библиотеку. – ryyker

+0

Фактически вызов memcpy() (как и большинство других функций в стандартной библиотеке) является потокобезопасным в C++ 11 (он может не реентерабельны, но это две разные вещи). Конечно, если вы используете memcpy для копирования памяти в/из места, к которому обращается другой поток, тогда эта операция вводит datarace, но это верно для любой функции, которая модифицирует важная часть состоит в том, что он не вводит скрытые dataraces (например, путем доступа к некоторому статическому буферу). – MikeMB

2

IMHO вы не должны концентрироваться на memcpy(), но на более высокую функциональность.

И memcpy() is поточно-безопасный, если отрегулированные интервалы памяти параллельных бегущих потоков не перекрываются. Практически в memcpy() существует только цикл for (;;) (с большим количеством оптимизаций) [по крайней мере, в glibc], это причина, почему она объявлена.

Если вы хотите знать, что будет делать ваши параллельные потоки memcpy(), вы должны представить циклы for (;;), которые копируют память через longint-указатели.

+1

Возможно, вы думаете, что он не является атомарным. – peterh

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