¿Cuál era el problema, en caso de que las personas tengan un problema similar: después de algunas discusiones con el soporte de Mathworks, resultó ser un conflicto entre el impulso del sistema y las bibliotecas de impulso enviadas de Matlab: cuando compilé con cabeceras de impulso del sistema y las conecté con bibliotecas de Matlab boost (más antiguas), fallaron. Cuando lo compilé y lo vinculé dinámicamente con el impulso del sistema, pero luego cargó dinámicamente las bibliotecas de Matlab boost, quedó colgado para siempre.colgar y/o segfault al usar boost :: threads desde matlab, no cuando se llama directamente
La vinculación estática con el sistema aumenta, al igual que la descarga de los encabezados correctos para la versión de refuerzo que se incluye con Matlab y la compilación de esos. Por supuesto, las compilaciones de Mac de Matlab no tienen números de versión en sus nombres de archivo, aunque las compilaciones de Linux y supuestamente de Windows sí. R2011b usa boost 1.44, como referencia.
que tienen algo de código multiproceso que funciona bien cuando se compila directamente, sino segfaults y/o bloqueos cuando se llama desde una interfaz mex
Matlab. No sé si el entorno diferente está revelando un defecto en mi código, o qué, pero no puedo resolverlo ...
Estoy ejecutando esto en tres configuraciones de máquina (aunque hay varias de las cajas de CentOS):
- OSX 10.7, g ++ 4.2, impulsar 1.48, Matlab R2011a (sonido metálico ++ 2.1 también funciona para independiente, no han tratado de conseguir mex utilizar sonido metálico)
- antigua CentOS, g ++ 4.1 .2, impulso 1.33.1 (depuración y no depuración), Matlab R2010b
- antiguo CentOS, g ++ 4.1.2, impulso 1.40 (no hay versiones de depuración instaladas), Matlab R2010b
Aquí hay una versión reducida con este comportamiento.
#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");
}
Tenga en cuenta que el impulso 1.48, consigo el mismo comportamiento si cambio el funtor en una función estándar y sólo tiene que pasar boost::ref
s a las exclusiones mutuas/datos como argumentos adicionales a boost::thread
. Boost 1.33.1 no es compatible con esto, sin embargo.
Cuando compilo directamente, siempre funciona muy bien - que nunca he visto fallar en cualquier situación:
$ 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
Ejecución de Matlab, he visto un montón de diferentes comportamientos después de hacer diferentes ajustes al código y demás, aunque no hay cambios que realmente tengan sentido para mí. Pero esto es lo que he visto con el código exacto arriba:
- en OSX/impulsar 1.48:
- Si está vinculada a un impulso de liberación variante, me sale un error de segmentación intentar acceder a un cercano 0 dirección dentro de
boost::thread::start_thread
, siendo llamado desde el constructort1
. - Si está vinculado a un impulso de depuración-variante, se cuelga para siempre en el primer
boost::thread::join
. No estoy del todo seguro, pero creo que los hilos de trabajo se han completado en este momento (no veo nada eninfo threads
que obviamente sean ellos).
- Si está vinculada a un impulso de liberación variante, me sale un error de segmentación intentar acceder a un cercano 0 dirección dentro de
- en CentOS/refuerzo 1.33.1 y 1.40:
- Con impulso de liberación, me sale un error de segmentación en
pthread_mutex_lock
, siendo llamados desde elboost::thread::join
ent1
. - Con refuerzo de depuración, se cuelga para siempre en
__lll_lock_wait
dentro depthread_mutex_lock
en el mismo lugar. Como se muestra a continuación, los hilos de trabajo se han completado en este punto.
- Con impulso de liberación, me sale un error de segmentación en
yo no sé hacer nada más con las violaciones de segmento, ya que nunca ocurrirá cuando tenga símbolos de depuración que realmente me puede decir lo que el puntero nulo es.
En el caso colgante-para siempre, me parece conseguir siempre algo como esto si estoy pasando a través de 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();
Eso seguro que se ve como ambos hilos están completos antes de la llamada a t1.join()
. Así que intenté agregar una llamada sleep(1)
en la sección "hacer trabajo" entre los bloqueos; cuando estoy pasando a través de la salida de las discusiones después de la llamada a t1.join()
y todavía cuelga siempre:
106 t1.join();
(gdb)
[Thread 0x47814940 (LWP 20255) exited]
[Thread 0x48215940 (LWP 20256) exited]
# still hanging
Si up
a la función doWork
, results
se rellena con los mismos resultados que la versión impresiones independientes en esta máquina, por lo que parece que todo lo que está pasando.
No tengo idea de qué está causando ninguno de los segfaults o el colgamiento loco, o por qué es que siempre funciona fuera de Matlab y nunca dentro, o por qué es diferente con/sin símbolos de depuración, y no tengo idea cómo proceder para resolver esto. ¿Alguna idea?
A sugerencia de @ alanxz, me he encontrado la versión independiente del código bajo herramientas memcheck, Helgrind, y DRD de valgrind:
- en CentOS utilizando valgrind 3.5, ninguna de las herramientas de dar cualquier errores no suprimidos
- En OSX utilizando valgrind 3.7:
- Memcheck no proporciona ningún error no suprimido.
- Helgrind se cuelga cuando se ejecuta en cualquier sistema binario (incluido, por ejemplo,
valgrind --tool=helgrind ls
) en OSX, quejándose de una instrucción no admitida. - DRD ofrece más de cien errores.
Los errores DRD son bastante inescrutable para mí, y aunque he leído el manual y así sucesivamente, no puede hacer ningún sentido. Aquí está la primera de ellas, en una versión del código en el que comentaba el segundo trabajador/hilo:
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)
Línea 66 es la construcción de la rosca, y el 72 es la llamada join
; no hay más que comentarios intermedios. Por lo que puedo decir, esto está diciendo que hay una carrera entre esa parte del hilo maestro y la inicialización del hilo de trabajo ...pero realmente no entiendo cómo es posible?
El resto de la salida de DRD is here; No estoy obteniendo nada de eso.
¿Ha intentado ejecutarlo en valgrind, [helgrind] (http://valgrind.org/docs/manual/hg-manual.html) o [DRD] (http://valgrind.org/docs/manual /drd-manual.html)? Eso podría revelar algunas pistas sobre qué está pasando. – alanxz
@alanxz Gracias por la sugerencia, no estaba al tanto de helgrind/DRD. He agregado algunos detalles sobre lo que dicen a la pregunta. Recibo errores DRD en OSX, pero no tengo idea de lo que significan, a pesar de leer el manual, etc. – Dougal
¿Alguien intentó configurar @rpath en un entorno similar a Linux? Actualmente tengo el mismo problema, estoy pensando que el mex debería hacer el aislamiento adecuado de sus dependencias. – Raffi