Qual è il problema, nel caso in cui le persone hanno un problema simile: dopo alcune discussioni con il supporto di Mathworks, si è rivelato essere un conflitto tra l'amplificatore di sistema e le librerie di boost spedite da Matlab: quando ho compilato le intestazioni di boost di sistema e collegato con le librerie di Matlab boost (più vecchie), ha un segfault. Quando ho compilato e collegato dinamicamente con system boost ma poi ha caricato dinamicamente le librerie di boost Matlab, è rimasto per sempre.hang e/o segfault quando si usa boost :: threads da MATLAB, non quando chiamato direttamente
Il collegamento statico a System Boost funziona, così come il download delle intestazioni corrette per la versione di boost che Matlab fornisce e che compila con quelle. Naturalmente, i build Mac di Matlab non hanno numeri di versione nei loro nomi di file, sebbene lo facciano Linux e presumibilmente le build di Windows. R2011b usa boost 1.44, come riferimento.
ho qualche codice multithread che funziona bene quando è compilato direttamente, ma segfaults e/o deadlock quando si chiama da un'interfaccia Matlab mex
. Non so se il diverso ambiente sta rivelando un difetto nel mio codice, o cosa, ma non riesco a capirlo ...
Sto eseguendo questo su tre configurazioni della macchina (anche se ci sono diversi delle scatole CentOS):
- OSX 10.7, g ++ 4.2, aumentare 1.48, Matlab R2011a (clang ++ 2.1 funziona anche per standalone, non hanno trovato a mex per usare clang)
- antica CentOS, g ++ 4.1 .2, boost 1.33.1 (debug e non debug), Matlab R2010b
- CentOS antico, g ++ 4.1.2, boost 1.40 (nessuna versione di debug installata), Matlab R2010b
Ecco una versione ridotta con questo comportamento.
#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");
}
Si noti che su impulso 1,48, ottengo lo stesso comportamento se cambio il funtore in una funzione standard e proprio passo boost::ref
s ai mutex/dati come argomenti extra per boost::thread
. Boost 1.33.1 non supporta questo, però.
Quando compilo direttamente, funziona sempre bene - non ho mai visto fallire in qualsiasi situazione:
$ 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
esecuzione da Matlab, ho visto un sacco di comportamenti diversi dopo aver apportato modifiche diverse al codice e così via, anche se nessuna modifica ha effettivamente senso per me. Ma ecco quello che ho visto con il codice esatta:
- su OSX/amplificare 1.48:
- Se è collegato ad una spinta release-variante, ho un segfault cercando di accedere a un quasi-0 indirizzo interno
boost::thread::start_thread
, chiamato dal costruttoret1
. - Se è collegato a un boost di debug-variante, si blocca per sempre nel primo
boost::thread::join
. Non ne sono del tutto sicuro, ma penso che i thread dei lavoratori abbiano effettivamente completato a questo punto (non si veda nulla ininfo threads
che è ovviamente loro).
- Se è collegato ad una spinta release-variante, ho un segfault cercando di accedere a un quasi-0 indirizzo interno
- su CentOS/boost 1.33.1 e 1.40:
- con boost rilascio, ottengo un segfault in
pthread_mutex_lock
, essere chiamato dalboost::thread::join
sut1
. - con boost di debug, si blocca per sempre in
__lll_lock_wait
all'internopthread_mutex_lock
nello stesso luogo. Come mostrato di seguito, i thread di lavoro hanno completato a questo punto.
- con boost rilascio, ottengo un segfault in
non so come fare qualcosa di più con i segfaults, dal momento che non hanno mai verificarsi quando ho simboli di debug che in realtà possono dirmi che cosa il puntatore nullo è.
Nel caso appeso per sempre, mi sembra di avere sempre una cosa del genere se sto passando attraverso in 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();
che sicuramente assomiglia a entrambi i thread sono completi prima della chiamata a t1.join()
. Così ho provato ad aggiungere una chiamata sleep(1)
nella sezione "doing work" tra i blocchi; quando sto passando attraverso, l'uscita discussioni dopo la chiamata a t1.join()
e si blocca ancora per sempre:
106 t1.join();
(gdb)
[Thread 0x47814940 (LWP 20255) exited]
[Thread 0x48215940 (LWP 20256) exited]
# still hanging
Se up
fuori alla funzione doWork
, results
è popolata con gli stessi risultati che la versione standalone stampe su questa macchina, quindi sembra che tutto ciò che sta attraversando.
Non ho idea di cosa stia causando né i segfaults né le pazzesche impiccagioni, o perché funzioni sempre fuori da Matlab e mai dentro, o perché sia diverso con/senza simboli di debug, e non ho idea come procedere nel capire questo. qualche idea?
A @ di alanxz suggerimento, ho eseguito la versione standalone del codice sotto strumenti memcheck, Helgrind e DRD di valgrind:
- su CentOS utilizzando valgrind 3.5, nessuno degli strumenti fornisce alcuna errori non soppressi.
- Su OSX utilizzando valgrind 3.7:
- Memcheck non dà alcun errore non soppresso.
- Helgrind blocca per me quando eseguito su qualsiasi binario (compresi ad esempio
valgrind --tool=helgrind ls
) su OSX, lamentano un'istruzione non supportato. - DRD dà oltre un centinaio di errori.
Gli errori DRD sono piuttosto imperscrutabile per me, e anche se ho letto il manuale e così via, non riesco a dare un senso a loro. Ecco il primo, su una versione del codice in cui ho commentato la seconda operaio/thread:
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)
linea 66 è la costruzione del filo, e il 72 è la chiamata join
; non c'è nient'altro che commenti in mezzo. Per quanto posso dire, questo sta dicendo che c'è una corsa tra quella parte del thread principale e l'inizializzazione del thread di lavoro ...ma non capisco davvero come sia possibile?
Il resto dell'uscita da DRD is here; Non ne ricaverò niente.
Hai provato a eseguirlo sotto valgrind, [helgrind] (http://valgrind.org/docs/manual/hg-manual.html) o [DRD] (http://valgrind.org/docs/manual /drd-manual.html)? Questo potrebbe rivelare alcuni indizi su cosa sta succedendo. – alanxz
@alanxz Grazie per il suggerimento, non ero a conoscenza di helgrind/DRD. Ho aggiunto alcuni dettagli su ciò che dicono alla domanda. Ottengo errori DRD su OSX, ma non ho idea di cosa significano, nonostante la lettura del manuale e così via ... – Dougal
Qualcuno ha provato a configurare @rpath in ambiente Linux simile? Attualmente ho lo stesso problema, penso che il Messico dovrebbe fare il corretto isolamento delle sue dipendenze. – Raffi