Co było problemem, na wypadek gdyby ludzie mieli podobny problem: po kilku dyskusjach ze wsparciem Mathworks, okazało się, że jest to konflikt pomiędzy wzmocnieniem systemu a dostarczonymi przez Matlaba bibliotekami boost: kiedy skompilowałem je z nagłówkami doładowania systemu i połączono z (starszymi) bibliotekami doładowania Matlab, uległo to uszkodzeniu. Kiedy skompilowałem i dynamicznie związałem się z podnoszeniem systemu, ale potem dynamicznie ładowałem biblioteki doładowania Matlaba, to było to na zawsze.zawiesić się i/lub segfault podczas używania boost :: threads z MATLAB, a nie gdy zostanie wywołany bezpośrednio
Statyczne połączenie z działaniem systemu działa, podobnie jak pobieranie poprawnych nagłówków dla wersji boost, którą Matlab dostarcza i kompiluje z tymi. Oczywiście kompilacje Maca w Matlabie nie mają numerów wersji w nazwach plików, chociaż Linux i podobno kompilacje Windowsa. R2011b używa doładowania 1.44, dla odniesienia.
Mam wielowątkowych kod, który działa prawidłowo, gdy jest kompilowany bezpośrednio, ale zwraca błąd i/lub zakleszczenia, gdy jest wywoływana z Matlab mex
interfejsu. Nie wiem, czy inne środowisko ujawnia błąd w moim kodzie, czy co, ale nie mogę tego rozgryźć ...
Używam tego na trzech konfiguracjach maszyn (choć jest ich kilka pól CentOS):
- OSX 10.7, g ++ 4.2, zwiększyć 1.48, Matlab R2011a (dzyń ++ 2.1 działa również na autonomiczny, nie próbowali uzyskać mex w użyciu szczęk)
- starożytną CentOS, g ++ 4.1 .2, zwiększenie 1.33.1 (debugowanie i nie debugowanie), Matlab R2010b
- starożytny CentOS, g ++ 4.1.2, doładowanie 1.40 (brak zainstalowanych wersji debugowania), Matlab R2010b
Oto krótka wersja tego zachowania.
#include <queue>
#include <vector>
#include <boost/thread.hpp>
#include <boost/utility.hpp>
#ifndef NO_MEX
#include "mex.h"
#endif
class Worker : boost::noncopyable {
boost::mutex &jobs_mutex;
std::queue<size_t> &jobs;
boost::mutex &results_mutex;
std::vector<double> &results;
public:
Worker(boost::mutex &jobs_mutex, std::queue<size_t> &jobs,
boost::mutex &results_mutex, std::vector<double> &results)
:
jobs_mutex(jobs_mutex), jobs(jobs),
results_mutex(results_mutex), results(results)
{}
void operator()() {
size_t i;
float r;
while (true) {
// get a job
{
boost::mutex::scoped_lock lk(jobs_mutex);
if (jobs.size() == 0)
return;
i = jobs.front();
jobs.pop();
}
// do some "work"
r = rand()/315.612;
// write the results
{
boost::mutex::scoped_lock lk(results_mutex);
results[i] = r;
}
}
}
};
std::vector<double> doWork(size_t n) {
std::vector<double> results;
results.resize(n);
boost::mutex jobs_mutex, results_mutex;
std::queue<size_t> jobs;
for (size_t i = 0; i < n; i++)
jobs.push(i);
Worker w1(jobs_mutex, jobs, results_mutex, results);
boost::thread t1(boost::ref(w1));
Worker w2(jobs_mutex, jobs, results_mutex, results);
boost::thread t2(boost::ref(w2));
t1.join();
t2.join();
return results;
}
#ifdef NO_MEX
int main() {
#else
void mexFunction(int nlhs, mxArray **plhs, int nrhs, const mxArray **prhs) {
#endif
std::vector<double> results = doWork(10);
for (size_t i = 0; i < results.size(); i++)
printf("%g ", results[i]);
printf("\n");
}
Zauważ, że na impuls 1,48, mam ten sam problem, jeśli zmienię funktor do standardowej funkcji i po prostu przekazać boost::ref
S do muteksy/danych jako dodatkowe argumenty do boost::thread
. Boost 1.33.1 nie obsługuje tego.
Kiedy skompilować go bezpośrednio, to zawsze działa poprawnie - Nigdy nie widziałem to nie w każdej sytuacji:
$ g++ -o testing testing.cpp -lboost_thread-mt -DNO_MEX
$ ./testing
53.2521 895008 5.14128e+06 3.12074e+06 3.62505e+06 1.48984e+06 320100 4.61912e+06 4.62206e+06 6.35983e+06
biegnącego z Matlab, widziałem dużo różnych zachowań po wprowadzeniu różnych poprawek do kodu i tak dalej, ale żadnych zmian, które faktycznie mają dla mnie sens. Ale oto co widziałem z dokładnym powyższym kodzie:
- na OSX/pobudzenia 1.48:
- Jeśli jest to związane z pobudzenia uwalniania wariantem, otrzymuję segfault próbuje uzyskać dostęp do niemal 0 adres wewnątrz
boost::thread::start_thread
, wywoływany z konstruktorat1
. - Jeśli jest powiązany z podbiciem z wariantem debugowania, zawsze zawiesza się na pierwszym
boost::thread::join
. Nie jestem do końca pewien, ale myślę, że wątki robocze zostały już w tym momencie zakończone (nie widzę niczego w tym, co to jestinfo threads
).
- Jeśli jest to związane z pobudzenia uwalniania wariantem, otrzymuję segfault próbuje uzyskać dostęp do niemal 0 adres wewnątrz
- CentOS/przypominającego 1.33.1 i 1.40:
- Z pobudzenia uwalniania, otrzymuję segfault w
pthread_mutex_lock
, nazywany odboost::thread::join
nat1
. - Po wzmocnieniu debugowania, zawiesza się na zawsze w
__lll_lock_wait
wewnątrzpthread_mutex_lock
w tym samym miejscu. Jak pokazano poniżej, wątki robocze zakończyły się w tym momencie.
- Z pobudzenia uwalniania, otrzymuję segfault w
nie wiem jak to zrobić nic więcej z naruszenia ochrony pamięci, ponieważ nigdy nie występuje, gdy mam symbole debugowania, że faktycznie może mi powiedzieć, co jest wskaźnikiem NULL.
W wiszące-forever przypadku, wydaje mi się, aby zawsze uzyskać coś takiego, jakbym przechodzeniu w GDB:
99 Worker w1(jobs_mutex, jobs, results_mutex, results);
(gdb)
100 boost::thread t1(boost::ref(w1));
(gdb)
[New Thread 0x47814940 (LWP 19390)]
102 Worker w2(jobs_mutex, jobs, results_mutex, results);
(gdb)
103 boost::thread t2(boost::ref(w2));
(gdb)
[Thread 0x47814940 (LWP 19390) exited]
[New Thread 0x48215940 (LWP 19391)]
[Thread 0x48215940 (LWP 19391) exited]
105 t1.join();
To wątpienia wygląda obu wątków są kompletne przed wywołaniem t1.join()
. Próbowałem więc dodać wywołanie sleep(1)
w sekcji "praca" między blokadami; kiedy jestem przechodzeniu, wyjście nici po wywołaniu t1.join()
i nadal wisi na zawsze:
106 t1.join();
(gdb)
[Thread 0x47814940 (LWP 20255) exited]
[Thread 0x48215940 (LWP 20256) exited]
# still hanging
Gdybym up
się do funkcji doWork
, results
jest wypełniana z tych samych wyników, że samodzielna wersja drukuje na ta maszyna, więc wygląda na to, co się dzieje.
Nie mam pojęcia, co powoduje któryś z segfaultów lub zwariowanego zawieszania się, lub dlaczego to zawsze działa poza Matlabem i nigdy w środku, lub dlaczego jest inaczej z/bez symboli debugowania, i nie mam pojęcia jak postępować w ustalaniu tego. jakieś pomysły?
AT @ alanxz sugestią, Zabrakło mi autonomiczną wersję kodu pod narzędzi memcheck, Helgrind i DRD Valgrind za:
- CentOS korzystających valgrind 3.5, żadne z narzędzi dać dowolny niezablokowane błędy.
- Na OSX przy użyciu valgrind 3.7:
- W memcheck nie występują żadne niezablokowane błędy.
- Helgrind zawiesza się dla mnie po uruchomieniu dowolnego systemu plików binarnych (w tym np.
valgrind --tool=helgrind ls
) w systemie OSX, narzekając na nieobsługiwane instrukcje. - DRD daje ponad sto błędów.
błędów DRD są całkiem niezbadane do mnie, i chociaż czytałem instrukcji i tak dalej, nie mogę żadnego sensu z nich. Oto pierwszy z nich, w wersji kodu gdzie zakomentowanym drugi robotnik/wątku:
Thread 2:
Conflicting load by thread 2 at 0x0004b518 size 8
at 0x3B837: void boost::call_once<void (*)()>(boost::once_flag&, void (*)()) (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x2BCD4: boost::detail::set_current_thread_data(boost::detail::thread_data_base*) (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x2BA62: thread_proxy (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x2D88BE: _pthread_start (in /usr/lib/system/libsystem_c.dylib)
by 0x2DBB74: thread_start (in /usr/lib/system/libsystem_c.dylib)
Allocation context: Data section of r/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib
Other segment start (thread 1)
at 0x41B4DE: __bsdthread_create (in /usr/lib/system/libsystem_kernel.dylib)
by 0x2B959: boost::thread::start_thread() (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x100001B54: boost::thread::thread<boost::reference_wrapper<Worker> >(boost::reference_wrapper<Worker>, boost::disable_if<boost::is_convertible<boost::reference_wrapper<Worker>&, boost::detail::thread_move_t<boost::reference_wrapper<Worker> > >, boost::thread::dummy*>::type) (thread.hpp:204)
by 0x100001434: boost::thread::thread<boost::reference_wrapper<Worker> >(boost::reference_wrapper<Worker>, boost::disable_if<boost::is_convertible<boost::reference_wrapper<Worker>&, boost::detail::thread_move_t<boost::reference_wrapper<Worker> > >, boost::thread::dummy*>::type) (thread.hpp:201)
by 0x100000B50: doWork(unsigned long) (testing.cpp:66)
by 0x100000CE1: main (testing.cpp:82)
Other segment end (thread 1)
at 0x41BBCA: __psynch_cvwait (in /usr/lib/system/libsystem_kernel.dylib)
by 0x3C0C3: boost::condition_variable::wait(boost::unique_lock<boost::mutex>&) (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x2D28A: boost::thread::join() (in /usr/local/boost/boost_1_48_0/stage/lib/libboost_thread-mt-d.dylib)
by 0x100000B61: doWork(unsigned long) (testing.cpp:72)
by 0x100000CE1: main (testing.cpp:82)
Linia 66 jest budowa nitki, a 72 jest wezwanie join
; nie ma nic oprócz komentarzy pomiędzy. O ile mogę powiedzieć, chodzi o wyścig pomiędzy tą częścią wątku głównego a inicjacją wątku roboczego ...ale tak naprawdę nie rozumiem, jak to jest możliwe?
Reszta wyjściu z DRD is here; Nic z tego nie wyciągnę.
Czy próbowałeś uruchomić go pod valgrind [Helgrind] (http://valgrind.org/docs/manual/hg-manual.html) lub [DRD] (http://valgrind.org/docs/manual /drd-manual.html)? To może ujawnić pewne wskazówki na temat tego, co się dzieje. – alanxz
@alanxz Dzięki za sugestię, nie byłem świadomy helgrind/DRD. Dodałem kilka szczegółów na temat tego, co mówią na to pytanie. Dostaję błędy DRD na OSX, ale nie mam pojęcia, co one oznaczają, pomimo przeczytania instrukcji itd. – Dougal
Czy ktoś próbował ustawić ścieżkę @rpath w środowisku podobnym do Linuksa? Obecnie mam ten sam problem, myślę, że mex powinien zrobić właściwą izolację swoich zależności. – Raffi