c# - Flags, loops and locks in async code -


what i'm trying create 'listener' listens several different tcp ports @ once, , pipes messages observers.

pseudo-ish code:

private bool _listen = false; public void start() {     _listen = true;     task.factory.startnew(() => listen(1);     task.factory.startnew(() => listen(2); }  public void stop() {     _listen = false; }  private async void listen(int port) {      var tcp = new tcpclient();      while(_listen)      {           await tcp.connectasync(ip, port);           using (/*networkstream, binaryreader, etc*/)           {                while(_listen)                {                    //read binary reader , onnext iobservable                }           }      } } 

(for brevity, i've omitted try/catch inside 2 whiles, both of check flag)

my question is: should locking flag, , if so, how tie-in async/await bits?

first of all, should change return type task, not void. async void methods fire-and-forget , can't awaited or cancelled. exist allow creation of asynchronous event handlers or event-like code. should never used normal asynchronous operations.

the tpl way cooperatively cancel/abort/stop asynchronous operation use cancellationtoken. can check token's iscancellationrequested property see if need cancel operation , stop.

even better, asynchronous methods provided framework accept cancellationtoken can stop them immediatelly without waiting them return. can use networkstream's readasync(byte[], int32, int32, cancellationtoken) read data , cancel immediatelly when calls stop method.

you change code this:

    cancellationtokensource _source;      public void start()     {         _source = new cancellationtokensource();                     task.factory.startnew(() => listen(1, _source.token),_source.token);         task.factory.startnew(() => listen(2, _source.token), _source.token);     }      public void stop()     {         _source.cancel();     }       private async task listen(int port,cancellationtoken token)     {         var tcp = new tcpclient();         while(!token.iscancellationrequested)         {             await tcp.connectasync(ip, port);             using (var stream=tcp.getstream())             {                 ...                 try                 {                     await stream.readasync(buffer, offset, count, token);                 }                 catch (operationcanceledexception ex)                 {                     //handle cancellation                 }                 ...             }         }     } 

you can read lot more cancellation in cancellation in managed threads, including advice on how poll, register callback cancellation, listen multiple tokens etc.

the try/catch block exists because await throws exception if task cancelled. can avoid calling continuewith on task returned readasync , checking iscanceled flag:

    private async task listen(int port,cancellationtoken token)     {         var tcp = new tcpclient();         while(!token.iscancellationrequested)         {             await tcp.connectasync(ip, port);             using (var stream=tcp.getstream())             {                 ///...                 await stream.readasync(buffer, offset, count, token)                     .continuewith(t =>                     {                         if (t.iscanceled)                         {                             //do cleanup?                         }                         else                         {                             //process buffer , send notifications                         }                     });                 ///...             }         }     } 

await awaits simple task finishes when continuation finishes