Замена фонового работника с заданием / асинхронным / ожидающим? - PullRequest
1 голос
/ 19 марта 2020

Мой код в настоящее время реализует двух фоновых рабочих, один для TX и один для RX. Оба запускаются асинхронно.

Как только я отправляю 7-байтовую команду TX, я должен получить 7-байтовый RX-ответ.

Если возможно, я бы хотел связать задачу приема байтов для отправки задача байтов, поскольку это только кажется логичным.

Я знаю, что фоновые работники устарели и хотели бы модернизировать код, используя Task-Parallel-Library .

Может кто-нибудь объяснить, как заменить обработчик события backgroundWorker_DoWork на асинхронную c задачу для описанного контекста?

Вот код:

    public static class MyService
    {
        public static byte[] binarySend, binaryReceive;
        public static string receive, send;
        public static BinaryReader binaryReader;
        public static BinaryWriter binaryWriter;
        public static TcpClient tcpClient;
        public static StreamReader streamReader;
        public static StreamWriter StreamWriter;
        public static NetworkStream NetworkStream;
        public static bool expReply, expAck = false;
        public static string ipAddress = "someIP";
        public static string portNo = "somePort";
        public static double currentZoomPos;
        public static BackgroundWorker backgroundWorkerRX, backgroundWorkerTX; 


        public static void ConnectCamera()
        {
            tcpClient = new TcpClient();
            backgroundWorkerRX = new BackgroundWorker();
            try
            {
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), int.Parse(port));
                tcpClient.Connect(endPoint);

                if (tcpClient.Connected)
                {
                    Console.WriteLine($"Connected to {ipAddress} port: {port}");
                    NetworkStream networkStream = tcpClient.GetStream();
                    binaryWriter = new BinaryWriter(networkStream);
                    binaryReader = new BinaryReader(networkStream);
                    // background worker1 
                    backgroundWorkerRX.RunWorkerAsync(); //-- start RX
                    backgroundWorkerRX.WorkerSupportsCancellation = true;
                }
            }
            catch (Exception ex) {Console.WriteLine("serial connection failed.");}
        }

        public static void QueryZoom()
        {
            // Send query zoom command via client using binary writer
            var tx_data = new byte[7] { 0xff, 0x01, 0x00, 0x55, 0x00, 0x00, 0x56};
            expReply = true;
            binarySend = tx_data;
            backgroundWorkerTX.RunWorkerAsync();
        }

        // RX data
        public static void backgroundWorkerRX_DoWork(object sender, DoWorkEventArgs e) 
        {
            if(backgroundWorkerRX.CancellationPending == true) {backgroundWorkerRX.CancelAsync();}

            while (tcpClient.Connected)
            {
                try
                {
                    if (expReply)
                    {
                        // What I need to return -- 
                        binaryReceive = binaryReader.ReadBytes(7);
                        {
                            if (binaryReceive[0] == 0xFF && binaryReceive[1] == 0x01)
                            {
                                if(binaryReceive[3] == 0x5D)
                                {
                                    currentZoomPos = (binaryReceive[4] * 256) + binaryReceive[5];
                                    Console.WriteLine($"Current Zoom position is: {currentZoomPos}");
                                }
                            }
                            binaryReceive = null;
                        }
                        expReply = false;
                    }
                }
                catch (Exception ex) {Console.WriteLine(ex.Message.ToString());}
            }
        }

        //TX data
        public static void backgroundWorkerTX_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                if (tcpClient.Connected)
                {
                    if (binarySend != null)
                    {
                        binaryWriter.Write(binarySend);
                        binarySend = null;
                    }
                }
            }
            catch (Exception ex) {Console.WriteLine(ex.Message.ToString());}
        }
    }

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Если вы всегда сначала отправляете байты, а затем получаете байты, вы можете использовать что-то вроде этого:

public static class NetworkStreamExtensions
{
    public static async Task<byte[]> SendReceiveBytes(this NetworkStream self, byte[] toSend, int bytesToReceive, CancellationToken cancel)
    {
        await self.WriteAsync(toSend, 0, toSend.Length, cancel);
        var receiveBuffer = new byte[bytesToReceive];
        var receivedBytes = await self.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cancel);

        if (receivedBytes != receiveBuffer.Length)
        {
            // Handle incorrect number of received bytes, 
        }

        return receiveBuffer;
    }
}

Поскольку это использует async / await, он будет использовать текущий контекст синхронизации для запуска кода , Т.е. при вызове в основном потоке он будет отправлять и получать в основном потоке. Тем не менее, он разрешает выполнение другого кода между записью и чтением, поскольку асин c методы не блокируют выполнение.

0 голосов
/ 19 марта 2020

Я думаю, что вы, вероятно, ищете:

TaskCompletionSource в System.Threading.Tasks

https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1?view=netframework-4.8

...