2016-05-30 10 views
1

Ich habe Threads, Nachrichten von einem rohen HCI-Buchse in einer Schleife wie folgt lautet:Warum wird read() nicht nach shutdown/close auf Raw-Socket zurückgegeben?

void* loop_hci (void* args) { 
    params_hci_t* params = (params_hci_t*) args; 
    int result_hci = 0; 
    uint8_t* buf_hci = calloc(1, HCI_EVENT_MAX_LENGTH); 
    while (!poll_end()) { 
     result_hci = read(params->hci_sock, buf_hci, HCI_EVENT_MAX_LENGTH); 
     if (result_hci > 0) { 
      // ... do stuff with the received data 
     } 
    } 
    ancs_pdebug("HCI loop shutting down..."); 
    return NULL;  
} 

Die poll_end() Funktion funktioniert und wie beabsichtigt. Es gibt 0 zurück, bis ein SIGINT-Signal empfangen wird, nach, dass es 1.

Im Hauptthread gibt erstelle ich die Fassung wie folgt aus:

hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 

Und auch das Thema:

ph->hci_sock = hci_sock; 
pthread_create(&t_hci, NULL, &loop_hci, ph); 

Dann nach einer Weile Call-Shutdown wie folgt (in den Haupt-Thread):

shutdown(hci_sock, SHUT_RD); 

Ich nehme an, lesen () sollte ich nach dem Aufruf von shutdown() zurückkehren, verwende ich die gleiche Methode in einem anderen Thread für einen L2CAP-Socket und es funktioniert gut. Aber das tut es nicht. Mein pthread_join(t_hci, NULL) Aufruf im Hauptthread kehrt nie zurück.

Die Steckdose funktioniert gut. Ich kann Nachrichten daraus lesen. Ich habe auch versucht, Schließen zu nennen (was ich tue, nachdem die Threads geendet haben), aber die Ergebnisse sind die gleichen.

Was könnte das Problem sein, oder sind meine Annahmen falsch?

+0

Sie * * * den Thread zu beenden? Sie überprüfen * nach 'read' um' 0' oder '-1' zurückzugeben? Wenn 'read' '0' oder '-1' zurückgibt, unterbricht man die Schleife oder beendet den Thread auf andere Weise? Und wenn möglich, versuchen Sie bitte, ein [minimales, vollständiges und überprüfbares Beispiel] (http://stackoverflow.com/help/mcve) zu erstellen und zeigen Sie uns. –

+0

Bevor ich shutdown anrufe, wird ein Flag gesetzt, so dass poll_end() 1 zurückgibt. Wenn das Ergebnis <= 0 ist, überspringe ich den Rest der Schleife. Nach dem Zurücklesen sollte die Schleife also selbständig unterbrochen werden. –

+0

Was lässt Sie denken, dass das Aufrufen von 'shudown()' auf einem Datei-Deskriptor, der von einem anderen Thread verwendet wird, überhaupt erlaubt ist? – EOF

Antwort

2

Das Problem, das Sie haben, könnte wegen der Art sein, wie Sie Sockets und Multithreading behandeln. Sie sollten das Herunterfahren mit rohen Sockets nicht verwenden. Es ist für angeschlossene Sockets gedacht, die ich wirklich nie mit rohen Sockets oder Packet Sockets ausprobiert habe. Aber es gibt einen Vorschlag, einen Thread zu töten oder abzubrechen, den ich vermeiden würde, weil das Töten eines Threads rohe Gewalt ist und Sie das Risiko haben, Ressourcen nicht in geordneter Weise zu entsorgen. Stattdessen sollten Sie Ihre Lösung in einer anderen Art und Weise gestalten:

  1. Eine Möglichkeit ist, nicht-blockierende Sockets zusammen mit ausgewählter, Umfrage oder epoll zu verwenden. Sie werden eine Schleife haben, die in select/poll/epoll wartet, bis ein Socket bereit ist oder ein Timeout auftritt. Wenn Sie einen Socket schließen wollen, setzen Sie einfach eine Variable, wie zum Beispiel endLoop auf true und geben an, dass der abfragende Thread die Schleife verlassen soll. Siehe man für select: http://man7.org/linux/man-pages/man2/select.2.html

  2. Andere Möglichkeit, die zum Beispiel in Thrift-Server verwendet wird, ist, dass die Anwendung eine spezielle Nachricht an sich selbst mit bestimmtem Code sendet. Der hörende Thread entsperrt und liest diese spezielle Nachricht, die anzeigt, dass er überprüfen sollte, ob er das Abhören beenden muss (indem er beispielsweise einen Variablenwert liest).

So, während er hört Thread oder Lesen hört, wird der Haupt-Thread die Variable EndLoop Variable auf true gesetzt, der anzeigt, es zu beenden, oder es wird tun (2), um das Hören Thread zu entsperren.

Die beiden Optionen sind elegante Möglichkeiten, mit Ihrem Problem umzugehen. Verwenden Sie entweder nicht blockierende Sockets (1) oder entsperren Sie den blockierten Lese- oder Empfangs-Thread, indem Sie eine Nachricht an sich selbst senden.

+0

@EJP, Entschuldigung für den Fehler. Ich bearbeite meine Antwort. – rodolk