简体   繁体   中英

How to keep an asynchronous program running?

I'm working on a program that uses S22 imap to keep an IDLE connection to gmail and receive messages real time.

I am calling the following function from my Main method:

static void RunIdle()
{
    using (ImapClient Client = new ImapClient("imap.gmail.com", 993, "user", "pass", AuthMethod.Login, true))
    {

        if (!Client.Supports("IDLE"))
            throw new Exception("This server does not support IMAP IDLE");

        Client.DefaultMailbox = "label";
        Client.NewMessage += new EventHandler<IdleMessageEventArgs>(OnNewMessage);
        Console.WriteLine("Connected to gmail");

        while (true)
        {
            //keep the program running until terminated
        }

    }
}

Using the infinite while loop works, but it seems there would be a more correct way to do this. In the future if I want to add more IDLE connections, the only way I see my solution working is with a separate thread for each connection.

What is the best way to accomplish what I am doing with the while loop?

Do not dispose of the client and root it in a static variable. That way it just stays running and keeps raising events. There is no need to have a waiting loop at all. Remove the using statement.

If this is the last thread in your program you indeed need to keep it alive.

Thread.Sleep(Timeout.Infinite);

What is the best way to accomplish what I am doing with the while loop?

You may want to do the following two things:

  1. Provide your RunIdle with a CancelationToken so that it can be cleanly stopped.
  2. In your busy waiting while loop, use Task.Delay to "sleep" until you need to "ping" the mailbox again.

     static async Task RunIdle(CancelationToken cancelToken, TimeSpan pingInterval) { // ... // the new busy waiting ping loop while (!cancelToken.IsCancellationRequested) { // Do your stuff to keep the connection alive. // Wait a while, while freeing up the thread. if (!cancelToken.IsCancellationRequested) await Task.Delay(pingInterval, cancelToken); } } 
  3. If you don't need to do anything to keep the connection alive, except from keeping the process from terminating:

    • Read from the console and wait until there is a ctrl + c or some clean "exit" command.

A simple solution that avoid thread blocking would be to just use Task.Delay() for some random amount of time.

static async Task RunIdle(CancellationToken token = default(CancellationToken))
{
    using (ImapClient Client = new ImapClient("imap.gmail.com", 993, "user", "pass", AuthMethod.Login, true))
    {

        ...

        var interval = TimeSpan.FromHours(1);
        while (!token.IsCancellationRequested)
        {
            await Task.Delay(interval, token);
        }
    }
}

Instead of while(true) you could perhaps use a CancellationToken in case the execution needs to be stop at some point. Task.Delay() supports this as well.

This are all solutions for a Console application, though. If running as a service, the service host will make sure your program keeps executing after starting, so you can just return.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM