2
votes

Ok I have a simulator which consists of some methods and a timer. I am starting the timer here :

private void StartSimulation(object sender,EventArgs e)
{ 
    while(execList.Count != 0)
    {
        Assign(MF,Mpre);
        retCT = ChooseTransition(execList);
        ttoexec = retCT[1];
        this.time = retCT[0];                     
        timer.Start();
        // I need to stop execution of this method here untill timer stops ticking
        ExecuteTransition(ttoexec);
        execList.Remove(ttoexec);
    }
}

And the timer method is like :

private void Timer_Tick(object sender,EventArgs e)
{
    --time;
    ++k;
    output.Add("t.u : " + k + "  " + "M = [" + MF.GetRowVal() + "];");
    if (time == 0)
    {
        timer.Stop();
    }
}

variable time is of type int and holds the number of seconds time needs to tick(is time * 1000 ms of the interval time of timer). Note that in StartSimulation method I am setting time with a value from an array.

Update

I am using a System.Windows.Forms.Timer

I want my StartSimulation() to stop executing until timer is stopped (until the execution of timer.Stop() in Timer_Tick).The output is a list of strings , which in the end I will write in a txt file .

The issue now is that the execution of StartSimulation() is going in same time as the timer ticks , therefore output list have only 1 element (that one I insert in the beginning of StartSimulation() code which I didn't paste it here).

So I open the txt file , write in it, close it and timer is still going. The execution of StartSimulation should stop when timer.Start() method is invoked

3
omg, use interpolation $"t.u : {k} M = [{MF.GetRowVal()}];" - TheGeneral
Also your question is not clear, please try to explain what you are trying to do, why its not working, and what you expect the outcome to be - TheGeneral
@TheGeneral Ok but that still does not help me to solve my issue :D - user3720015
Also what sort of timer is this? there are several in .net - TheGeneral
@TheGeneral How clear you want ? I want my StartSimulation() to stop executing until timer is stopped( until the execution of timer.Stop() in Timer_Tick). output is a list of strings , which in the end I will write in a txt file . The issue now is that the execution of StartSimulation() is going in same time as the timer ticks , therefore output list have only 1 element( that one I insert in the beginning of StartSimulation() code which I didn't paste it here). So I open the txt file , write in it, close it and timer is still going. The execution of StartSimulation should stop when timer.Star - user3720015

3 Answers

2
votes

You can check the Enabled property.

According to the official documentation, Stops raising the Elapsed event by setting Enabled to false.

1
votes

Ok somehow I managed to get it working , will post the code here in case someone need to implement something similar:

 private void Timer_Tick(object sender,EventArgs e)
    {
        --time;
        ++k;

        if (time == 0)
        {
            ExecuteTransition(ttoexec);
            output.Add($"t.u : {k} M = [{MF.GetRowVal()}];");
            timer.Stop();
        }
        else
        {
            output.Add($"t.u : {k} M = [{MF.GetRowVal()}];");
        }

    }
    private bool isDone()
    {
        while (true)
        {
            if (!timer.Enabled) return true;
        }
    }
    private Task DoAsync()
    {
        return Task.Factory.StartNew(() => isDone());
    }

  private async void StartSimulation(object sender,EventArgs e)
  {  
    ...
    await DoAsync(); // it won't go further unless method isDone() return anything
    ...
   }
0
votes

Ok, without refactoring your code too much, and sticking to the original spirit of the question.

As you are on the UI thread, one solution is to use async await pattern to keep the UI responsive, and AutoResetEvent. Unfortunately AutoResetEvent is not awaitable, however you can build your own

Given

public class AsyncAutoResetEvent
{
   private static readonly Task _completed = Task.FromResult(true);
   private readonly Queue<TaskCompletionSource<bool>> _waits = new Queue<TaskCompletionSource<bool>>();
   private bool _signaled;

   public Task WaitAsync()
   {
      lock (_waits)
      {
         if (_signaled)
         {
            _signaled = false;
            return _completed;
         }

         var tcs = new TaskCompletionSource<bool>();
         _waits.Enqueue(tcs);
         return tcs.Task;
      }
   }

   public void Set()
   {
      TaskCompletionSource<bool> toRelease = null;

      lock (_waits)
         if (_waits.Count > 0)
            toRelease = _waits.Dequeue();
         else if (!_signaled)
            _signaled = true;

      toRelease?.SetResult(true);
   }
}

Usage

private AsyncAutoResetEvent asyncAutoResetEvent = new AsyncAutoResetEvent();

...

private async Task StartSimulation(object sender, EventArgs e)
{
   while (execList.Count != 0)
   {
      Assign(MF, Mpre);
      retCT = ChooseTransition(execList);
      ttoexec = retCT[1];
      this.time = retCT[0];
      timer.Start();

      // stop here and leaves the UI responsive
      // until its set again
      await AsyncAutoResetEvent.WaitAsync();

      ExecuteTransition(ttoexec);
      execList.Remove(ttoexec);
   }
}

private void Timer_Tick(object sender,EventArgs e)
{
    --time;
    ++k;
    output.Add("t.u : " + k + "  " + "M = [" + MF.GetRowVal() + "];");
    if (time == 0)
    {
        timer.Stop();
        AsyncAutoResetEvent.Set();
    }
}

Note : You will need to propagate the async await backwards through your code with this solution

Disclaimer : There is really other ways to do what you want to do using tasks and a plethora of different reorganizations of your code, though this should work