[C#] BeginAccept niet asynchroon?

Pagina: 1
Acties:

  • decipherer
  • Registratie: Februari 2002
  • Laatst online: 23:11
Ik heb een applicatie gemaakt welke gebruik maakt van asynchrone sockets. Tenminste, dat dacht ik.

In de documentatie vind ik dat de thread waarop de callback van BeginAccept uitgevoerd wordt een thread uit de (IOCP) threadpool is. Af en toe gebeurt dit ook, maar soms (als er veel binnenkomende verbindingen zijn) wordt de callback uitgevoerd op dezelfde thread als waarop ik BeginAccept aanroep.

Dit lijkt me geen asynchroon gedrag, er wordt immers geen tweede thread gebruikt voor de afhandeling van de callback.

Ik zou hier graag een verklaring voor hebben. Is dit een feature of een bug? Ik kan er verder niks van vinden.

Onderstaand is een stukje code om te testen:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System;
using System.IO;

namespace TestAsyncSockets
{
    public class AsyncTest
    {
        private ManualResetEvent connectionAccepted = new ManualResetEvent(false);
        TextWriter logger = new StreamWriter("async.log");

        public AsyncTest()
        {
        }

        public void Start()
        {
            Thread listenthread = new Thread(new ThreadStart(StartListening));
            listenthread.Start();

            Thread sendthread1 = new Thread(new ThreadStart(StartSending));
            sendthread1.Start();

            Thread sendthread2 = new Thread(new ThreadStart(StartSending));
            sendthread2.Start();
        }

        private void StartListening()
        {
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 5456);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.Bind(localEndPoint);
            socket.Listen(20);

            while (true)
            {
                connectionAccepted.Reset();
                logger.WriteLine("Listening thread id: " + Thread.CurrentThread.ManagedThreadId.ToString() + ", ThreadPoolThread: " + Thread.CurrentThread.IsThreadPoolThread.ToString()); logger.Flush();
                socket.BeginAccept(new AsyncCallback(this.AcceptCallback), null);
                connectionAccepted.WaitOne();
             }
        }

        /*
            Deze methode wordt some op listenthread uitgevoerd, soms op een thread uit de threadpool
        */
        private void AcceptCallback(IAsyncResult ar)
        {
            int threadPoolThreads;
            int completionPortThreads;
            ThreadPool.GetAvailableThreads(out threadPoolThreads, out completionPortThreads);

            int maxThreadPoolThreads;
            int maxCompletionPortThreads;
            ThreadPool.GetMaxThreads(out maxThreadPoolThreads, out maxCompletionPortThreads);

            logger.WriteLine(String.Format("Receiver thread id: {0}, Nr of threads in Threadpool: {1}, {2}, Max threads in ThreadPool: {3}, {4}, ThreadPoolThread: {5}", Thread.CurrentThread.ManagedThreadId, threadPoolThreads, completionPortThreads, maxThreadPoolThreads, maxCompletionPortThreads, Thread.CurrentThread.IsThreadPoolThread)); logger.Flush();
            connectionAccepted.Set();
        }

        private void StartSending()
        {
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    socket.Connect(IPAddress.Loopback, 5456);
                    socket.Disconnect(false);
                    //Thread.Sleep(5);
                }
                catch
                {
                }
            }
        }
    }
}


Een gedeelte van de output van async.log ziet er zo uit:

code:
1
2
3
4
Listening thread id: 12, ThreadPoolThread: False
Receiver thread id: 12, Nr of threads in Threadpool: 25, 1000, Max threads in ThreadPool: 25, 1000, ThreadPoolThread: False
Listening thread id: 12, ThreadPoolThread: False
Receiver thread id: 16, Nr of threads in Threadpool: 25, 999, Max threads in ThreadPool: 25, 1000, ThreadPoolThread: True

De beste ideeën komen als je bezig bent.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Als dat het geval is dan zou je IAsyncResult.CompletedSynchronously true moeten zijn.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • decipherer
  • Registratie: Februari 2002
  • Laatst online: 23:11
Klopt! En zoeken op CompletedSynchonously leverde ook wat nuttige informatie op, het is me een stuk duidelijker nu.

Blijkbaar was het dus geen slim idee om in de callback van BeginAccept een synchrone receive te plaatsen die vervolgens de verbinding open hield en dus de thread blokkeerde. :P

De beste ideeën komen als je bezig bent.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
DeCIpHeReR schreef op donderdag 03 mei 2007 @ 09:08:
Klopt! En zoeken op CompletedSynchonously leverde ook wat nuttige informatie op, het is me een stuk duidelijker nu.

Blijkbaar was het dus geen slim idee om in de callback van BeginAccept een synchrone receive te plaatsen die vervolgens de verbinding open hield en dus de thread blokkeerde. :P
Ik zou inderdaad gewoon meteen alles asynchroon doen. Gewoon een state object maken en die mee geven. Als je een keer perse op het afronden van een asynchrone functie moet wachten kan je gebruik maken van de AsyncWaitHandle.

Een andere optie zou zijn om te controleren of hij synchroon gecomplete wordt en dan zelf op een andere thread uit te voeren.

Ik had het zelf trouwens nog nooit meegemaakt dat de operatie synchroon gecomplete werd, dus wel leuk om te weten dat het ook daadwerkelijk kan gebeuren.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”