.Net : Ukončení Threadu v době kdy provádí blokující volání

Jack

Dobrý den, chtěl jsem si naprogramovat takový malý P2P chat, ale zaseknul jsem se na jedné věci  - když chce uživatel ukončit chat v době, kdy čeká thread na pozadí na Accept, nevím jak to ukončení korektně udělat.

Mám:

Kód: [Vybrat]
        private Thread _listenThread;
        private bool _programRunning = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void ListenThread()
        {
            var receiveBuffer = new byte[1024];

            var mainReceiveSocket = new TcpListener(new IPEndPoint(new IPAddress(new byte[] { 127, 0, 0, 1 }), 1234));

            mainReceiveSocket.Start();

            TcpClient tcpClient = null;
            Socket clientSocket = null;

            while (_programRunning)
            {
                do
                {
                    clientSocket = null;

                    tcpClient = mainReceiveSocket.AcceptTcpClient();

                    clientSocket = tcpClient.Client;

                } while ((clientSocket == null) || (!clientSocket.Connected && _programRunning));

                while (_programRunning)
                {
                    clientSocket.Receive(receiveBuffer);

                    var message = System.Text.Encoding.Default.GetString(receiveBuffer);
                }
            }
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
            _programRunning = true;

            _listenThread = new Thread( new ThreadStart(ListenThread));

            _listenThread.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _programRunning = false;

            _listenThread.Join();
        }

Když nastavím _programRunning na false, tak to logicky nestačí, protože AcceptTcpClient čeká, dokud se nedočká.

Jak to děláte vy, prosím?
« Poslední změna: 18. 09. 2016, 19:28:56 od Petr Krčmář »


javaman ((

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #1 kdy: 18. 09. 2016, 16:21:40 »
My to děláme v Javě a říkáme vláknu, ať se zastaví a to se pak řeší dál.

v

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #2 kdy: 18. 09. 2016, 16:31:52 »
nejčastěji neblokující volání ve smyčce + sleep

Jack

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #3 kdy: 18. 09. 2016, 16:39:58 »
Ano, exisuje AcceptTcpClientAsync + pridat ve smycce sleep - toto nemam vyzkousene - nevim jak se asynchronni metoda bude chovat - snad kdybych v podmince smycky kontroloval property connected. zda se mi, ze kdybych pouzil await, bude to jako predtim.

jeste jsem zkousel nastavit threadu IsBackground = true a pak volat pri skonceni programu thread.Interrupt v try/catch bloku, protoze interrupt a abort vyhodi vyjimku.

Ky pristup tedy preferovat? dekuji

Radek Miček

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #4 kdy: 18. 09. 2016, 16:55:08 »
Když nastavím _programRunning na false, tak to logicky nestačí, protože AcceptTcpClient čeká, dokud se nedočká.

Na mainReceiveSocket je třeba zavolat metodu Stop(). To způsobí vyhození výjimky, kterou byste měl spolknout.

Tedy mainReceiveSocket vytáhnout z metody ListenThread do třídy a Form1_FormClosing upravit na:

Kód: [Vybrat]
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _programRunning = false;
            _mainReceiveSocket.Stop();
            _listenThread.Join();
        }


Rado2

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #5 kdy: 18. 09. 2016, 16:59:19 »
Zrovna so socketmi som v c# ešte nerobil, ale od .NET4 práve na IO operácie je najlepšie programovať asynchrónne, je zbytočné vôbec vytvárať na toto thready.
Našiel som tento príklad (prvá odpoveď).
http://stackoverflow.com/questions/12630827/using-net-4-5-async-feature-for-socket-programming


alfonzo

Re:.Net : Ukončení Threadu v době kdy provádí blokující volání.
« Odpověď #6 kdy: 18. 09. 2016, 17:59:45 »
treba pouzivat asyn/await.

offtopic:
pozna niekto Jana Pluskala?

JmJ

  • ****
  • 315
    • Zobrazit profil
Re:.Net : Ukončení Threadu v době kdy provádí blokující volání
« Odpověď #7 kdy: 19. 09. 2016, 08:36:51 »
Jak uz tady po ruznu zaznelo:

a) pokud mozno nedelat dlouhe blokujici operace
b) u socketu jde pouzit asynchronni accept
c) pokud se socket, na kterem je volano listen, zavren, pak je operace listen prerusena
d) pokud chci pri ukoncovani aplikace ukoncovat jeji vlakna, pak jim zpravidla dam nejaky cas a pokud se neukonci ani tak, tak nezbyva nez Thread.Abort(). Je to ale poslednis stace, rozhodne to neni doporuceno jako bezny zpusob ukonceni vlakna, protoze to muze mit vedlejsi ucinky.  Kolikrat je lepsi "zaseknute" vlakno nechat nekde hnit delsi cas, jestli se fakt nevzpamatuje a pak ho teprve abortovat. Tohle ale zalezi na konkretni situaci.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:.Net : Ukončení Threadu v době kdy provádí blokující volání
« Odpověď #8 kdy: 16. 10. 2016, 15:12:19 »
Dobrý den, chtěl jsem si naprogramovat takový malý P2P chat, ale zaseknul jsem se na jedné věci  - když chce uživatel ukončit chat v době, kdy čeká thread na pozadí na Accept, nevím jak to ukončení korektně udělat.

Mám:

Kód: [Vybrat]
        private Thread _listenThread;
        private bool _programRunning = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void ListenThread()
        {
            var receiveBuffer = new byte[1024];

            var mainReceiveSocket = new TcpListener(new IPEndPoint(new IPAddress(new byte[] { 127, 0, 0, 1 }), 1234));

            mainReceiveSocket.Start();

            TcpClient tcpClient = null;
            Socket clientSocket = null;

            while (_programRunning)
            {
                do
                {
                    clientSocket = null;

                    tcpClient = mainReceiveSocket.AcceptTcpClient();

                    clientSocket = tcpClient.Client;

                } while ((clientSocket == null) || (!clientSocket.Connected && _programRunning));

                while (_programRunning)
                {
                    clientSocket.Receive(receiveBuffer);

                    var message = System.Text.Encoding.Default.GetString(receiveBuffer);
                }
            }
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
            _programRunning = true;

            _listenThread = new Thread( new ThreadStart(ListenThread));

            _listenThread.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _programRunning = false;

            _listenThread.Join();
        }

Když nastavím _programRunning na false, tak to logicky nestačí, protože AcceptTcpClient čeká, dokud se nedočká.

Jak to děláte vy, prosím?
Stačí zavřít poslouchající socket a vlákno pak ukončit standardně (vyskočit ze smyčky a následně z funkce). Takto to funguje ve všech jazycích, protože BSD sockety.