2016-06-15 7 views
1

ich Operationen auf einer STL Karte in den folgenden Funktionen, die alle durch einen Mutex geschützt sind: -Segfault in C++ stl Karte durch statische Variable Bereinigung während des Prozessausganges

static std::mutex track_active_lock_mtx; 
typedef intrusive_ptr<WatchCtxInternal> WatchCtxInternal_h; 
static std::map<WatchCtxInternal*, WatchCtxInternal_h> actives; 
void* get_ptr(WatchCtxInternal_h ctx) 
{ 
    unique_lock<mutex> trackActiveLock(track_active_lock_mtx); 
    if(actives.find(ctx.get()) == actives.end()) { 
     actives.insert(make_pair(ctx.get(), ctx)); 
    }  
    trackActiveLock.unlock(); 
    return ctx.get(); 
} 

void genericWatcher(void *watcherCtx) 
{ 
    unique_lock<mutex> trackActiveLock(track_active_lock_mtx); 
    auto it = actives.find((WatchCtxInternal*)watcherCtx); 
    if (it == actives.end()) {   
     return; 
    } 
    //do unrelated stuff 
    actives.erase(it); 
} 

ich eine Segmentierung bekam Fehler in der ersten Funktion: -

Program terminated with signal SIGSEGV, Segmentation fault. 
#0 _M_lower_bound (this=<optimized out>, __k=<optimized out>, __y=0xf31256e8, __x=0x65687465) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1261 
1261   if (!_M_impl._M_key_compare(_S_key(__x), __k)) 
(gdb) bt 
#0 _M_lower_bound (this=<optimized out>, __k=<optimized out>, __y=0xf31256e8, __x=0x65687465) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1261 
#1 find (__k=<optimized out>, this=0xf6ac8e2c <actives>) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_tree.h:1913 
#2 find (__x=<optimized out>, this=0xf6ac8e2c <actives>) at /volume/evo/files/opt/poky/1.8.2-4/sysroots/i586-poky-linux/usr/include/c++/4.9.2/bits/stl_map.h:860 
#3 get_ptr (ctx=...) 
(gdb)fr 3 
(gdb) p ctx 
$4 = {px = 0xf3124d30} 

EDIT: Ich habe es geschafft, eine Stack-Trace mit dem Memcheck-Tool zu bekommen. Was geschieht, ist, dass die statische Karte wird als Teil des Prozesses Ausfahrt gereinigt, aber ein Rückruf zu genericWatcher wird in dem anderen Thread auftreten, bevor sie vollständig austritt: -

main.cpp

static void thread1(void *arg) { 
    //call genericWatcher repeatedly 
} 

int main() { 
    if(fork() == 0) { 
     pthread_create(..., thread1,..) 
     //call get_ptr() repeatedly 
    } 
    return 0; 
} 

Gibt es irgendeinen Weg, dies zu verhindern? Ich konnte ein Singleton zuteilen, die die Wirkstoffe Karte hält, aber ich versuche mit Singletons zu vermeiden

+2

Valgrind dies ... – Velkan

+0

konnte nicht reproduzieren mit aktuellen Unit-Test –

+1

Ihr Beispiel-Code soll minimal aber vollständig sein! Niemand kann deine Probleme so reproduzieren. –

Antwort

0

Die wahrscheinlichste Fehlerpunkt ist der erase Anruf in Ihrem release Rückruf, weil es der einzige Zugang zu Ihrer Karte ist, die nicht bekommen hat jeder Schutzmechanismus. Sind Sie sicher, dass Ihr WatchCtx Teil der Kartenschlüssel ist? Wenn nicht, ist es möglich, dass der Einsatz bereits loslässt. Aber, wie Velkan bereits gesagt hat, wird Valgrind (oder dein Debugger der Wahl) dir Sicherheit geben.

+1

Ist es nicht durch den unique_lock geschützt? Vielleicht habe ich missverstanden, wie das funktioniert –

+0

@Bug Killer das Schloss schützt die Karte vor Mehrfachzugriff zur gleichen Zeit. Es schützt es nicht vor dem Schlüssel, den Sie ihm geben, der nicht in der Karte ist, um mit zu beginnen (zum Beispiel, wenn es nie richtig hinzugefügt wurde). Ich kenne den Kontext des Programms nicht und rufe Beschränkungen so weit auf, um dies zu verifizieren oder zu verfälschen. Wenn Sie vor dem Aufruf von 'find' den Schlüssel mit 'löschen' markieren und der Fehler nicht mehr auftritt, werde ich Ihre Einfüge-Routinen oder die Art und Weise, wie Sie bestimmen, welche' WatchCtx' Sie wann entfernen, betrachten. – starturtle

+0

Ich denke, Anruf mit einem nicht existenten Schlüssel löschen ist sicher: [695754] –