2013-08-02 13 views
5

Buduję wspólną bibliotekę, która wewnętrznie korzysta z Boost.thread. W rezultacie Boost.system jest również używany, ponieważ zależy od tego Boost.thread. Moja udostępniona biblioteka eksportuje interfejs C, więc chcę ukryć całą moją obsługę wyjątków wewnętrznych i użycie wątku itp. Od użytkownika końcowego. To ma być czarna skrzynka. Jednak gdy łączę się z aplikacją kliencką, gdy program działa poprawnie - gdy tylko nadejdzie czas, aby zatrzymać przetwarzanie przez wywołanie funkcji bibliotecznej, otrzymuję:Wewnętrzne wyjątki w bibliotece współdzielonej kończą aplikację użytkownika końcowego.

zakończyć wywołanie po rzuceniu wystąpienia "boost :: thread_interrupted" "

Przechwytuję ten wyjątek wewnętrznie w bibliotece, więc nie mam pojęcia, dlaczego tak naprawdę nie zostanie złapany. Program użytkownika końcowego w żaden sposób nie ma na celu informowania się o wyjątkach funkcji Boost ani o nich nie traktuj. Podczas budowania współużytkowanej biblioteki używam statycznego linkowania zarówno dla Boost.thread, jak i Boost.system, więc świat zewnętrzny nigdy nie jest przeznaczony do ich wyświetlania. Jestem na GCC 4.7 na Ubuntu 12. W Windowsie nie mam takich problemów (ani z MSVC, ani z MinGw).

(EDIT)

Mam pytanie do edycji pokazują minimalistyczny przykład, który reprodukuje problemu, zgodnie z wnioskami w komentarzach.

Tutaj pierwszy kod dla testlib.cpp i testlib.h.

testlib.cpp:

 
#include <boost/thread/thread.hpp> 

void thread_func() 
{ 
while(1) 
{ 
boost::this_thread::interruption_point(); 
} 
} 

void do_processing() 
{ 
// Start a thread that will execute the function above. 
boost::thread worker(thread_func); 

// We assume the thread started properly for the purposes of this example. 

// Now let's interrupt the thread. 
worker.interrupt(); 

// And now let's wait for it to finish. 
worker.join(); 
} 

A teraz testlib.h:

 
#ifndef TESTLIB_H 
#define TESTLIB_H 

void do_processing(); 

#endif 

buduję ten w udostępnionej biblioteki za pomocą następującego polecenia:

g ++ -static-libgcc - static -s -DNDEBUG -I/usr/boost_1_54_0 -L/usr/boost_1_54_0/stage/lib -Wall -shared -fPIC -o libtestlib.so testlib.cpp -lboost_thread -lboost_system -lpthread -O3

Wtedy, mam kod trywialny program kliencki, który wygląda następująco:

 
#include "testlib.h" 
#include <cstdio> 

int main() 
{ 
do_processing(); 
printf("Execution completed properly.\n"); 
return 0; 
} 

zbudować klienta w następujący sposób:

g ++ -DNDEBUG -I/usr/boost_1_54_0 -L ./ -Wall -o client.cpp klient -ltestlib -O3

Kiedy uruchomić klienta, otrzymuję:

terminate nazywany po wrzuceniu instancją 'boost :: thread_interrupted'
Przerwano (core dumped)

Nie zauważam wyjątku wyjątku przerwania wątku, ale zgodnie z dokumentacją Boost Boost.thread robi to i kończy tylko dany wątek. Próbowałem jawnie wychwycić wyjątek z wewnątrz funkcji thread_func, ale to nie miało znaczenia.

(koniec edycji)

(EDIT 2)

Warto zauważyć, że nawet z -fexceptions włączona, problem nadal występuje.Próbowałem także rzucić i złapać wyjątek zdefiniowany w tej samej jednostce tłumaczeniowej, co kod, który ją przechwytuje i wyrzuca, bez żadnej poprawy. Krótko mówiąc, wszystkie wyjątki wydają się pozostawać niezabezpieczone we wspólnej bibliotece, mimo że zdecydowanie mam dla nich obsługę przechwytywania. Kiedy kompiluję plik klienta i plik testlib jako część pojedynczego programu, to znaczy bez tworzenia testlib do współużytkowanej biblioteki, wszystko działa zgodnie z oczekiwaniami.

(koniec EDIT 2)

Wszelkie wskazówki?

+6

Proponuję wykonać *** minimalny test ***, który demonstruje problem (pomyśl o 5-liniowym pliku Makefile). Połóż to na github/gist. Możliwe, że znajdziesz przyczynę/obejście tego procesu. Jeśli nie, faktycznie będziesz miał coś, co nam pokaże. – sehe

+2

@ komentarze takie jak to powinno być nieskończenie wznawiane, szczególnie w przypadku "Są szanse, znajdziesz przyczynę/obejście w procesie". Niezliczone są czasy, w których zacząłem zadawać pytanie na temat SO, aby znaleźć rozwiązanie, próbując zdobyć minimalną ilość kodu reprodukcyjnego. – stijn

+0

@stijn Wiem. Szczerze mówiąc, powiedziałem to tylko dlatego, że dosłownie nie mamy innej opcji, poza dziką zgadywanką, jak jest teraz. Naprawdę chcę w tym pomóc, ale nie ma co dalej. – sehe

Odpowiedz

1

W końcu to rozgryzłem. Flaga -statyczna nigdy nie powinna być określona, ​​gdy podano -shared. Wierzyłem, że po prostu powiedział linkerowi, aby preferował statyczne wersje bibliotek, które łączy, ale zamiast tego sprawia, że ​​wygenerowana biblioteka dynamiczna nie nadaje się do dynamicznego łączenia, co jest nieco ironiczne. Ale tak jest. Usunięcie -static rozwiązało wszystkie moje problemy i jestem w stanie połączyć statycznie po prostu w mojej dynamicznej bibliotece, która doskonale obsługuje wyjątki.

0

Może this?

Jeśli biblioteka L, który rzuca E, a następnie obie L i aplikacja A MUSI być połączone przeciwko X, biblioteka zawierająca definicję E.

Spróbuj połączyć plik wykonywalny przeciwko doładowanie.

+0

Niestety, to nie zadziała dla mnie. Biblioteka jest przeznaczona dla użytkowników końcowych, a wszystkie wewnętrzne zależności są statycznie połączone, aby aplikacja kliencka nie musiała się nimi martwić. Egzekwowanie zależności od Boost nie byłoby możliwe. –

+0

Aby wyjaśnić jeszcze bardziej, aplikacja (a) nie powinna wiedzieć o e. Powinienem zarówno rzucać, jak i łapać w różnych częściach siebie, ale nigdy nie powinno się widzieć e. –

0

Wspólna biblioteka, która sama zawiera statycznie połączone biblioteki, nie jest dobrym pomysłem i nie sądzę, aby ten scenariusz był dobrze obsługiwany w pakiecie narzędzi GNU.

Myślę, że Twój szczególny problem wynika z opcji -static-libgcc, ale nie udało mi się skompilować go w mojej maszynie z Twoimi opcjami. Nie dlatego, że łączenie statycznie-dinamicznie z dźwiękami libpthread.so jest tak dobrym pomysłem albo ... Co się stanie, jeśli główny plik wykonywalny chce tworzyć własne wątki? Czy zostanie skompilowany z -pthread? Jeśli tak, to połączysz dwa razy funkcje wątków; jeśli nie, będzie miał funkcje, ale nie makroprocesory wstępne ani funkcje biblioteki wątkowej.

Moja rada to po prostu nie kompilować biblioteki statycznie, to po prostu nie jest sposób Linuksa.

Właściwie to nie powinno być prawdziwym problemem, nawet jeśli nie chcesz polegać na wersji dystrybucyjnej doładowania: skompilować program przeciwko współdzielonych bibliotek Boost i wdrożyć wszystkie te pliki (libboost_thread.so.1.54.0, libboost_system.so.1.54.0 i libtestlib.so) do ten sam katalog. Następnie uruchom program za pomocą LD_LIBRARY_PATH=<path-to-so-files>. Ponieważ klient nie jest przeznaczony do bezpośredniego zwiększania mocy, nie potrzebuje nagłówków doładowania, ani nie łączy ich w komendzie kompilatora. Nadal masz swoją czarną skrzynkę, ale teraz jest utworzona przez 3 *, więc pliki, zamiast tylko 1.

+0

Nawet wyjątki, które są zgłaszane wewnątrz mojej biblioteki, które są zadeklarowane w tej bibliotece, są nieprzechwycone. Zdarza się to bez włączania funkcji Boost i dzieje się tak, gdy nie ma opcji -static-libgcc. Zmuszenie użytkownika do dodania Boost nie jest czymś, co chcę zrobić, to nie jest już czarne pole, jeśli użytkownik musi dbać o swoje wewnętrzne zależności. Dynamiczne łączenie z pthreads jest w porządku, ale Boost to inna historia. Chociaż, jak wspomniałem, problem wyjątku jest obecny nawet bez wzmocnienia, nawet jeśli typ wyjątku jest zdefiniowany, wyrzucony i przechwycony wewnątrz samej biblioteki. –

Powiązane problemy