简体   繁体   中英

What is the best way to delay a console application for a few seconds

Overview.

I have a Windows Service written in C# .NET 4.0 that is hooking into the Betfair API to place bets automatically (all betting decisions are done in the SQL DB). The service has a number of timers that sets up some polling for 3 main areas (place pending bets, check prices, place in play bets [during the race]). The timers are all triggered every 30 seconds.

The one I am having difficulty with is the InPlay betting one. Once every 30 seconds the timer calls a method in my BetfairBot object that checks for upcoming races that have inplay bets for them. There could be multiple systems betting on the same race so I wanted to fire off the "control" method in parrallel so one system isn't waiting for the other to finish before being able to place its bets.

So I have some code like this to fire off the parallel control methods

// some SQL to get my upcoming races
DataTable sqlRecordset = this.dataAccess.GetDataTable(SQL);

try
{

// run in parallel for each system and concurrent races

Parallel.ForEach(sqlRecordset.AsEnumerable(), recordsetRow =>
{

    betfairLogon = recordsetRow["BetfairLogon"].ToString();
    betfairPassword = recordsetRow["BetfairPassword"].ToString();
    SystemPK = Convert.ToInt32(recordsetRow["SystemPK"]);
    systemName = recordsetRow["SystemName"].ToString();
    RacePK = Convert.ToInt32(recordsetRow["RaceFK"]);

    // spawn thread for each system    
    this.RunInPlayBettingControl(SystemPK, betfairLogon, betfairPassword, systemName, RacePK);

});


}
catch (Exception e)
{
// log error
HelperLib.LogMsg("Error starting Parallel Threads for RacePK: " + RacePK.ToString() + " - " +e.Message.ToString());
}

Then in my control method I loop until the betting is over, calling another method which handles the betting and returns a result code telling my system the status of the betting eg whether the race has finished, not started yet, or just about to start.

On a couple of these statuses I want to delay my thread for a couple of seconds before re-calling the betting method.

I have tried

Thread.Sleep(2500);

But this doesn't wait at all and the betting proc is called instantly again without waiting.

I have read up a bit about threading and I don't know whether the problem is with my Parallel loop that triggers parallel calls to my control method (which needs to delay the thread on demand) or with my control method and the Thread.Sleep(delay) call.

My initial timers that are in the Service class work fine and I don't know the best way of going about this or what the problem is with the delaying as I presumed each Thread initiated by the Parallel loop would be running on its own and therefore delayed with a .Sleep call if required.

Should I use more timers OR another method, and what is the best way with my existing loop code?

The Control method fired by the Parallel loop is below. The code for the actual betting method is too complicated to post here but it has no thread calls just some SQL and some calls to the Betfair API.

Any help would be much appreciated. Thanks in advance.

public void RunInPlayBettingControl(int SystemPK,string betfairLogon, string betfairPassword, string systemName, int RacePK)
{
int result = 0;
bool quit = false; // we loop until true

// decode our encrypted logon details
betfairPassword = HelperLib.GetPassword(betfairLogon);
betfairLogon = HelperLib.DecodeLogon(betfairLogon);

// create API object
this.betfairAPI = new BetfairAPI(systemName);

// try and log in for this system and save the session for future use

if (!String.IsNullOrEmpty(betfairLogon) && !String.IsNullOrEmpty(betfairPassword))
{

// check logged in status as we might have used previous session otherwise log in now
if (!this.betfairAPI.IsLoggedIn() && this.betfairAPI.Login(betfairLogon, betfairPassword) == false)
{
    // couldnt login so exit
    return;
}
else
{                  

    // save session to file
    this.betfairAPI.SaveSession(systemName);

    // we loop until we know there is no more point in doing so
    while (!quit)
    {
    // result code values
    // 0 = We have no idea whats going on yet
    // 1 = Race is actually closed/finished so exit
    // 2 = Race is inplay but we are not ready to bet yet - wait a short while
    // 3 = Race is inplay and ready to bet
    // 4 = Race is not inplay yet so wait a bit and carry on

    // this is our main betting method that handles all our betting
    result = this.RunInPlayBetting(SystemPK, betfairLogon, betfairPassword, systemName, RacePK);

    // check result to see if we quit looping
    switch (result)
    {
        case 1:
        // race is over so exit
        quit = true;
        break;
        case 2:
        // race is in play but not over our marker yet so go back in after a short wait
         Thread.Sleep(1000);  // NOT WORKING
        quit = false;

        break;
        case 3:
        // race is in play so lets go straight back in and try some more betting
        quit = false; 
        break;
        case 4:
        // not in play yet so keep looping after a short wait
        quit = false;

        Thread.Sleep(2500); // NOT WORKING

        break;

        case 0:
        // have no idea whats going just quit loop
        quit = true;
        break;

    }
    }
}

}   

return;
}

Thread.Sleep(2500);

But this doesn't wait at all and the betting proc is called instantly again without waiting.

Thread.Sleep() will suspend the current thread for the specified time. What you are seeing is other threads executing the same method (I assume you have a breakpoint there for checking), since you spawned a bunch of them with Parallel.ForEach() .

I am not totally sure what you're after. Do you want to be able to temporarily stop all new calls to RunInPlayBettingControl method? If yes then you must do threads synchronization. Do it like that:

class XYZ
{
  Object syncObj = new Object();
  ...

  public void RunInPlayBettingControl(int SystemPK,string betfairLogon, string betfairPassword, string systemName, int RacePK)
  {
    lock(this.syncObj)
    { }
    ...

    switch(...)
    {
      ...
      case 2:
      // race is in play but not over our marker yet so go back in after a short wait
      lock(this.syncObj)
      {
          Thread.Sleep(1000);
      }
      ...
    }
  }
}

This way you will hold any new calls to RunInPlayBettingControl but running ones will finish.

Is this any helpful?

Generally though you should avoid calling Thread.Sleep because during that time thread is in lock wait state and it would prevent application from exiting (unless it is background thread).

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