2012-06-09 11 views
5

Ich habe einen Code, der eine pthread spawns, die versucht, eine Socket-Verbindung zu einem Remote-Host aufrechtzuerhalten. Wenn die Verbindung jemals unterbrochen wird, versucht sie, die Verbindung mit einem blockierenden connect()-Aufruf an ihrem Socket wiederherzustellen. Da der Code in einem separaten Thread ausgeführt wird, interessiert mich nicht die Tatsache, dass es die synchrone Socket-API verwendet.Wie unterbricht man einen Thread, der eine blockierende Socket-Verbindung durchführt?

Das heißt, bis es Zeit für meine Anwendung zum Beenden kommt. Ich möchte einen gewissen Anschein eines geordneten Herunterfahrens machen, also verwende ich Thread-Synchronisations-Primitive, um den Thread aufzuwecken und zu signalisieren, dass er beendet wird, dann führe einen pthread_join() auf dem Thread aus, um darauf zu warten, dass er beendet wird. Das funktioniert großartig, es sei denn, der Thread ist in der Mitte eines connect() Aufrufs, wenn ich das Herunterfahren befehle. In diesem Fall muss ich auf die Verbindung warten, bis die Zeit abgelaufen ist, was sehr lange dauern könnte. Dies führt dazu, dass das Herunterfahren der Anwendung lange dauert.

Was ich tun möchte ist, den Anruf zu connect() in irgendeiner Weise zu unterbrechen. Nachdem der Anruf zurückkehrt, wird der Thread mein Beendigungssignal bemerken und sauber herunterfahren. Da connect() ein Systemaufruf ist, dachte ich, dass ich es möglicherweise absichtlich unterbrechen könnte, indem ich ein Signal verwende (wodurch der Aufruf EINTR zurückkehrt), aber ich bin nicht sicher, ob dies eine robuste Methode in einer POSIX-Thread-Umgebung ist.

Hat jemand irgendwelche Empfehlungen, wie dies zu tun ist, entweder mit Signalen oder über eine andere Methode? Beachten Sie, dass der Aufruf connect() in einem Bibliothekscode nicht möglich ist, den ich nicht ändern kann. Daher ist das Wechseln zu einem nicht blockierenden Socket keine Option.

+2

Bitte legen Sie auch ein Sprachkennzeichen. – Tudor

+0

Ich schreibe eigentlich in Python, aber ich suche nichts Sprachspezifisches. Sie können davon ausgehen, dass ich unter Linux arbeite. –

+1

Schließen Sie die Steckdose. –

Antwort

6

Try close() der Sockel der connect() zu unterbrechen. Ich bin mir nicht sicher, aber ich denke, es wird zumindest unter Linux funktionieren. Natürlich vorsichtig sein, so dass Sie immer nur schließen() dieses Socket einmal oder eine zweite close() könnte theoretisch einen nicht verwandten Datei-Deskriptor, der gerade geöffnet wurde schließen.

EDIT: Abschaltung() könnte besser geeignet sein, weil es eigentlich nicht die Steckdose in der Nähe.

Alternativ können Sie auch einen Blick auf pthread_cancel() und pthread_kill() werfen. Allerdings sehe ich keine Möglichkeit, diese beiden ohne eine Race-Bedingung zu verwenden.

Ich empfehle, dass Sie den Multithread-Server-Ansatz aufgeben und stattdessen ereignisgesteuert werden, z. B. epoll für Ereignisbenachrichtigung verwenden. Auf diese Weise können Sie all diese sehr grundlegenden Probleme vermeiden, die bei Threads sehr schwierig werden, wie zB ein ordnungsgemäßes Herunterfahren. Sie können jederzeit alles tun, was Sie wollen, z. Schließen Sie sicher die Buchsen und hören Sie nie wieder von ihnen.

Auf der anderen Seite, wenn in Ihrem Arbeitsthread haben Sie einen nicht-blockierende connect() und erhält über epoll_pwait gemeldet() (oder ppoll() oder pselect(); beachten Sie die p), können Sie Race-Bedingungen im Zusammenhang mit Signalen vermeiden.

+0

Danke für den Vorschlag, 'close()' zu verwenden; Ich werde mir das ansehen. Ich stimme zu, dass ein ereignisgesteuerter Mechanismus besser wäre.Wie ich jedoch in meiner Frage angemerkt habe, "ist der' connect() 'Aufruf in irgendeinem Bibliothekscode, den ich nicht ändern kann, nicht verfügbar. Daher ist das Wechseln zu einem nicht blockierenden Socket keine Option." –

+0

Der Teil "Kann nicht modifizieren" sollte hier ein großes Problem darstellen. Wie ich schon sagte, seien Sie vorsichtig, wenn Sie nicht zweimal schließen. Die Bibliothek möchte möglicherweise schließen() es nach connect() zurückgibt. Haben Sie darüber nachgedacht, den Prozess mit Gewalt zu beenden, wenn Sie mit all Ihren Aufgaben fertig sind, und sicherstellen, dass sich der invasive Code bis zu diesem Punkt nicht falsch verhält? –

+2

Ich ging mit Ihrem Vorschlag, 'shutdown()' zu verwenden. Da die Bibliothek in Python geschrieben ist, kann ich einen Blick auf den zugrunde liegenden Socket werfen und ihn anschließend herunterfahren. Es läuft gut. Nicht der beste Ansatz aus Sicht der Softwarearchitektur, aber hier funktioniert es, und ich habe die Kontrolle über die Version der Bibliothek, die verwendet wird. –