none
Mutual interference occur between multiple timer RRS feed

  • Question

  • My program creates multiple timers(System.Timers.Timer)

    Each timer in the main program(CompoundTimer) calls the static method which handle the value passed from the main program(This static method is in the static class and compiled as a separate dll(Common.dll))

    When I create first timer and then create second timer without delay, the value is not increased sequentially.

    However I put the sleep() between first timer and second timer, the value is increased sequentially.

    Judging by this symptom, mutual interference seems to occur between each timer.

    Here is the source code and result.

    using System; using System.Collections.Generic; using System.Text; namespace CompoundTimer { static public class Common { static public int GetIncreasedTotal(int value) { value = value + 1; return (value); } static public void WriteLog(string message) { using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\CSharpSample\CompoundTimer\bin\Release\Log.txt", true)) { file.WriteLine(DateTime.Now.ToLongTimeString() + " " + message); } } } }

    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace CompoundTimer
    {
        public partial class Form1 : Form
        {
            System.Timers.Timer tt1;
            System.Timers.Timer tt2;
            private int value = 0;
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                tt1 = new System.Timers.Timer();
                tt1.AutoReset = false;
                tt1.Interval = 1000;
                tt1.Elapsed += OnTimedEvent1;
                tt1.AutoReset = true;
                tt1.Enabled = true;
                tt1.Start();
    
                System.Threading.Thread.Sleep(100);//<========= result is different according to the existence of this line
    
                tt2 = new System.Timers.Timer();
                tt2.AutoReset = false;
                tt2.Interval = 1000;
                tt2.Elapsed += OnTimedEvent2;
                tt2.AutoReset = true;
                tt2.Enabled = true;
                tt2.Start();
            }
            private void OnTimedEvent1(Object source, System.Timers.ElapsedEventArgs e)
            {
                value = Common.GetIncreasedTotal(value);
                Common.WriteLog("OnTimedEvent1 : " + value.ToString());
            }
            private void OnTimedEvent2(Object source, System.Timers.ElapsedEventArgs e)
            {
                value = Common.GetIncreasedTotal(value);
                Common.WriteLog("OnTimedEvent2 : " + value.ToString());
            }
        }
    }

    With Sleep(100), the value is increased sequentially like following.

    3:51:31 PM   OnTimedEvent1 : 1
    3:51:31 PM   OnTimedEvent2 : 2
    3:51:32 PM   OnTimedEvent1 : 3
    3:51:32 PM   OnTimedEvent2 : 4
    3:51:33 PM   OnTimedEvent1 : 5
    3:51:33 PM   OnTimedEvent2 : 6
    3:51:34 PM   OnTimedEvent1 : 7
    3:51:34 PM   OnTimedEvent2 : 8
    3:51:35 PM   OnTimedEvent1 : 9
    3:51:35 PM   OnTimedEvent2 : 10
    3:51:36 PM   OnTimedEvent1 : 11
    3:51:36 PM   OnTimedEvent2 : 12
    3:51:37 PM   OnTimedEvent1 : 13
    3:51:37 PM   OnTimedEvent2 : 14
    3:51:38 PM   OnTimedEvent1 : 15
    3:51:38 PM   OnTimedEvent2 : 16
    3:51:39 PM   OnTimedEvent1 : 17
    3:51:39 PM   OnTimedEvent2 : 18

    However, without sleep(100), the value is not sequentially increased.

    I guess there was some mutual intterference between those two timers.

    Here is the result.

    3:48:07 PM   OnTimedEvent1 : 1
    3:48:08 PM   OnTimedEvent1 : 3
    3:48:09 PM   OnTimedEvent2 : 6
    3:48:10 PM   OnTimedEvent1 : 7
    3:48:11 PM   OnTimedEvent2 : 10
    3:48:12 PM   OnTimedEvent2 : 12
    3:48:13 PM   OnTimedEvent1 : 13
    3:48:14 PM   OnTimedEvent1 : 15
    3:48:15 PM   OnTimedEvent1 : 17
    3:48:16 PM   OnTimedEvent2 : 19
    3:48:17 PM   OnTimedEvent1 : 20
    3:48:18 PM   OnTimedEvent1 : 22
    3:48:19 PM   OnTimedEvent2 : 25
    3:48:20 PM   OnTimedEvent1 : 26
    3:48:21 PM   OnTimedEvent1 : 28
    3:48:22 PM   OnTimedEvent1 : 29
    3:48:23 PM   OnTimedEvent2 : 32
    3:48:24 PM   OnTimedEvent2 : 34
    Is there any way to make it work correctly without sleep()?

    Thursday, July 18, 2019 8:15 PM

Answers

  • According to log file, it seems that some of WriteLine fail when file is in use by another event handler. The documentation for Elapsed also says that the exceptions are suppressed.

    In order to solve the logging problem, and if you cannot yet use Interlocked.Add and Interlocked.Increment, then check one of approaches:

    private void OnTimedEvent1( object source, System.Timers.ElapsedEventArgs e )
    {
        lock( this )
        {
            value = Common.GetIncreasedTotal( value );
            Common.WriteLog( "OnTimedEvent1 : " + value );
        }
    }
     
    private void OnTimedEvent2( object source, System.Timers.ElapsedEventArgs e )
    {
        lock( this )
        {
            value = Common.GetIncreasedTotal( value );
            Common.WriteLog( "OnTimedEvent2 : " + value );
        }
    }




    Friday, July 19, 2019 5:25 AM
  • The 'correct' way to solve the issue depends on the complete context of the code and the exact problem it's causing. My post above was trying to explain why what was going wrong was going wrong, so you can make an informed decision.

    Normally, when you think you have a use for Sleep, you should think again and decide not to do it. And if you still think your case might be an exception and using Sleep might really be correct, you should think yet again and still decide not to do it. But very, very occasionally, there might just be legitimate uses for Sleep, and yes, this might just be one of them.

    • Marked as answer by Jeff0803 Thursday, July 25, 2019 5:34 PM
    Friday, July 19, 2019 3:07 AM

All replies

  • Hi,

    you can try it with this:

    Interlocked.Add(ref int location1, int value);

    Greetings,

    Chris


    • Edited by DerChris88 Thursday, July 18, 2019 8:54 PM
    • Marked as answer by Jeff0803 Friday, July 19, 2019 2:50 AM
    • Unmarked as answer by Jeff0803 Friday, July 19, 2019 2:50 AM
    Thursday, July 18, 2019 8:53 PM
  • Greetings Jeff.

    Timers are generally only accurate to about 20 milliseconds. Without the Sleep, your code sets two timers going well within that limit. This means it is not certain they will fire in order. So, for example, timer1 might fire first, followed by timer2, then timer2 again because it gets in a couple of milliseconds before timer1 due to the 20ms uncertainty. You then have the timers operating on the same data (value) which is bound to cause erratic behavior.

    Putting in the call to Sleep ensures the timers fire one after the other, in the order you expect, because they are now more than 20ms apart.

    • Marked as answer by Jeff0803 Friday, July 19, 2019 2:50 AM
    • Unmarked as answer by Jeff0803 Friday, July 19, 2019 2:50 AM
    Friday, July 19, 2019 12:03 AM
  • Ho can I apply Interlocked.Add() to my code?

    I need more in detail.

    Friday, July 19, 2019 2:51 AM
  • Do you mean using Sleep(100) is correct way to solve this issue?
    Friday, July 19, 2019 2:54 AM
  • The 'correct' way to solve the issue depends on the complete context of the code and the exact problem it's causing. My post above was trying to explain why what was going wrong was going wrong, so you can make an informed decision.

    Normally, when you think you have a use for Sleep, you should think again and decide not to do it. And if you still think your case might be an exception and using Sleep might really be correct, you should think yet again and still decide not to do it. But very, very occasionally, there might just be legitimate uses for Sleep, and yes, this might just be one of them.

    • Marked as answer by Jeff0803 Thursday, July 25, 2019 5:34 PM
    Friday, July 19, 2019 3:07 AM
  • According to log file, it seems that some of WriteLine fail when file is in use by another event handler. The documentation for Elapsed also says that the exceptions are suppressed.

    In order to solve the logging problem, and if you cannot yet use Interlocked.Add and Interlocked.Increment, then check one of approaches:

    private void OnTimedEvent1( object source, System.Timers.ElapsedEventArgs e )
    {
        lock( this )
        {
            value = Common.GetIncreasedTotal( value );
            Common.WriteLog( "OnTimedEvent1 : " + value );
        }
    }
     
    private void OnTimedEvent2( object source, System.Timers.ElapsedEventArgs e )
    {
        lock( this )
        {
            value = Common.GetIncreasedTotal( value );
            Common.WriteLog( "OnTimedEvent2 : " + value );
        }
    }




    Friday, July 19, 2019 5:25 AM