none
Observable.Interval becomes frozen when system time changed

    Discuţie generală

  • If there are subscriptions on Observable.Interval and system time has been changed for example one minute backward we get delay approximately of one minute for notifications. This delay appears again when system time is restored to original value. Behaviour of the last case looks very strange for me, because in case if system time changed forward immediately after the subscription, I don't see any delays. I think it is bug because documentation  doesn't say anything about such behaviour and Threading.Timer works fine in this situation.

    Here is code to reproduce this behaviour:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reactive;
    using System.Reactive.Disposables;
    using System.Reactive.Linq;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Threading;
    
    namespace cs_observable_interval_bug {
    	class Program {
    
    		[StructLayout(LayoutKind.Sequential)]
    		private struct SYSTEMTIME {
    			public ushort wYear;
    			public ushort wMonth;
    			public ushort wDayOfWeek;
    			public ushort wDay;
    			public ushort wHour;
    			public ushort wMinute;
    			public ushort wSecond;
    			public ushort wMilliseconds;
    		}
    
    		[DllImport("kernel32.dll", EntryPoint = "GetSystemTime", SetLastError = true)]
    		private extern static void Win32GetSystemTime(ref SYSTEMTIME lpSystemTime);
    
    		[DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
    		private extern static uint Win32SetSystemTime(ref SYSTEMTIME lpSystemTime);
    
    		static DateTime GetSystemTime() {
    			var systime = new SYSTEMTIME();
    			Win32GetSystemTime(ref systime);
    			return new DateTime(
    				systime.wYear, systime.wMonth, systime.wDay,
    				systime.wHour, systime.wMinute, systime.wSecond,
    				systime.wMilliseconds, DateTimeKind.Utc
    			);
    		}
    
    		static bool SetSystemTime(DateTime newDateTime) {
    			var systime = new SYSTEMTIME() {
    				wYear = (ushort)newDateTime.Year,
    				wMonth = (ushort)newDateTime.Month,
    				wDay = (ushort)newDateTime.Day,
    				wDayOfWeek = (ushort)newDateTime.DayOfWeek,
    				wHour = (ushort)newDateTime.Hour,
    				wMinute = (ushort)newDateTime.Minute,
    				wSecond = (ushort)newDateTime.Second,
    				wMilliseconds = (ushort)newDateTime.Millisecond
    			};
    			return Win32SetSystemTime(ref systime) != 0;
    		}
    
    		static void Main(string[] args) {
    			using (var subscription = new SerialDisposable()) {
    				var originTime = GetSystemTime();
    				var originTimeTs = Stopwatch.GetTimestamp();
    				Console.WriteLine("Current UTC system date-time: {0}", DateTime.UtcNow);
    				Console.WriteLine("press any key to change sytem date time, and then again to restore it back");
    				subscription.Disposable =
    					Observable.Interval(TimeSpan.FromMilliseconds(200))
    					.Subscribe(t => {
    						Console.Write(".");
    					}, err => {
    						Console.Write("$");
    					}, () => {
    						Console.Write("*");
    					});
    				Console.ReadKey(true);
    				SetSystemTime(originTime.AddMinutes(-1));
    				Console.WriteLine("\nsystem time changed");
    				Console.ReadKey(true);
    				Console.WriteLine("\nrestoring system time");
    				var delta = Stopwatch.GetTimestamp() - originTimeTs;
    				SetSystemTime(originTime.AddTicks(delta));
    				Console.WriteLine("\npress any key to exit");
    				Console.ReadKey(true);
    			}
    		}
    	}
    }



    6 aprilie 2012 12:21

Toate mesajele