2016-05-03 11 views
0

Ich mache eine Art Shell: Abhängig vom Benutzereintrag muss ich eine Funktion aufrufen. Ich kann den Inhalt dieser aufgerufenen Funktionen nicht ändern, da mein Programm nur ein Client ist und keine Sichtbarkeit hat.Wie man einen Funktionsaufruf "unterbricht"?

Aber ich möchte die Möglichkeit für den Benutzer, den Anruf mit CTRL+C zu beenden. Hier ist der minimale Code:

#include <csignal> 
#include <iostream> 
#include <unistd.h> 

void do_thing(void) 
{ 
    std::cout << "entering in do_thing()\n"; 
    while(42) 
     ::sleep(1); 
} 

extern "C" { 
    void signal_handler(int); 
} 

class Shell 
{ 
    friend void signal_handler(int); 

    public: 
     static Shell & Instance(void) 
     { 
      static Shell instance; 
      return instance; 
     } 
     int run(void) 
     { 
      std::string  buff; 
      while ((std::cin >> buff)) 
      { 
       if (buff == "foo") 
        do_thing(); // this must be terminable 
       else 
        std::cout << "(nothing)\n"; 
      } 
      return 0; 
     } 

    private: 
     Shell(void) 
     { 
      ::signal(SIGINT, signal_handler); 
     } 
     void signal(int sig) 
     { 
      if (sig == SIGINT) 
       ;// must terminal the function call 
     } 
}; 

extern "C" { 
    void signal_handler(int sig) 
    { 
     Shell::Instance().signal(sig); 
    } 
} 

int main(void) 
{ 
    return Shell::Instance().run(); 
} 

I drei Möglichkeiten in Betracht gezogen:

  • ich versuchte, eine Thread-Klasse von std::thread, mit einem kill() Verfahren abgeleitet zu schaffen, die eine Ausnahme ausgelöst. Der Funktionsaufruf befindet sich in einem try-catch-Block. Es funktioniert, aber das ist eine schlechte Lösung, da der Destruktor nicht aufgerufen werden kann und die Ressource niemals freigegeben wird.
  • Ich überlegte, fork zu verwenden, aber ich denke, es ist ein Overkill, nur die Möglichkeit zu erhalten, einen Funktionsaufruf zu unterbrechen.
  • Ich habe versucht, eine Ausnahme von der Signal-Handler zu werfen, aber ich sah, dass dies eine schlechte Idee ist, da dies sehr Compiler/Betriebssystem abhängigen Code ist.

Wie können Sie das Ding machen? Was ist die bessere Lösung?

Hinweis: Ich löschte den alten Beitrag, weil es in der Nähe angefordert wurde, und berücksichtigt die C/C++ - Tags.

+5

Habe ich diese Minuten nicht gelesen? –

+0

Einer der Punkte von Ausnahmen und Stapelabwickeln ist, dass Objekte außerhalb des Bereichs liegen und normal zerstört werden.Nicht, dass es sowieso eine Rolle spielt, da die Ausnahme in Ihrem Thread und nicht im Kontext des Threads, der Ihren "Befehl" ausführt, geworfen wird. –

+3

Es ist nicht möglich, einen Funktionsaufruf abzubrechen, noch ist es möglich, einen Thread zu beenden (Ihre 'kill()' Methode kann das unmöglich tun --- Sie scheinen eine ungewöhnliche Definition von "Arbeiten" zu haben und vielleicht eine Art Missverständnis von C++ - Ausnahmen). Der einzige (ja, der ** der ** der ** einzige **) Weg, einen Ausführungsablauf zu haben, der von außen abgebrochen werden kann, unabhängig davon, wofür ein separater Prozess erstellt werden soll. Also ja, 'fork()'. –

Antwort

2

Im Wesentlichen, nein, gibt es keinen Standard warum einen Thread in C++ zu unterbrechen. Threads laufen kooperativ und müssen daher die Kontrolle "aufgeben".

Wenn der Code für do_thing änderbar war, dann können Sie ein Flag (atomare) erstellen, um zu signalisieren, dass der Thread aufgeben und beenden sollte. Dies kann periodisch vom Thread überprüft und bei Bedarf vervollständigt werden.

der Code Da für do_thing nicht änderbar ist, ein kleines Fenster der Gelegenheit ist es, die verwendet werden können, um „zu töten“ oder „Abbrechen“, um den Faden (wenn auch nicht „Standard“ sein wird und Unterstützung wird auf gezielte Plattformen beschränkt).

std::thread bietet eine Funktion zum Abrufen einer native_handle(), die Implementierung definiert ist. Einmal erhalten (und konvertiert), kann es zum Töten oder Abbrechen des Threads verwendet werden.

gewarnt; Neben dem plattformspezifischen Code, der benötigt wird, lassen die Thread-Abschlüsse die Objekte auf diesem Thread im Allgemeinen "limbo" und damit die von ihnen gesteuerten Ressourcen.

+0

Danke für die Antwort. Ich bin unter GNU/Linux (Debian); aber das Programm kann unter anderen Distro (wie Ubuntu) verwendet werden. Es wird jedoch immer mit 'g ++' kompiliert. – Boiethios

+0

Sie müssen den Typ überprüfen, der von 'native_handle()' für alle Zieltypen zurückgegeben wird - es ist die Implementierung definiert. Aber da sie höchstwahrscheinlich auf Pthread basieren werden, ist das 'pthread_t 'höchstwahrscheinlich in allen Fällen. – Niall

+0

Ich denke, ich werde die C Pthread-Bibliothek verwenden, wie Sie vorschlagen. Es scheint schnell und ist tragbar, wenn ich die Dokumentation gut lese. – Boiethios