|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
MemoryAccessViolationException and multimedia timer problemI have imported the Multimedia timer funcs from "winmm.dll" and setup a c# class with the TimerEventHandler:- class MSecTmer { ulong count; // holds tick count of timer <stuff> private void tickHandler(int id, int msg, int userdata, int r1, int r2) { count++; // private ulong holding tick count // now call listeners (from other classes) waiting on the given time period if (onTimePeriod != null) onTimePeriod(); } It works to a point. The listeners get called for a certain number of iterations and then a MemoryAccessViolation exception occurs - always at the same number of iterations. I really know very little about the InteropServices namespace and about wrapping dll functions. I read somewhere in the docs that the callback should not include any system calls, so I commented out all but the increment and it *appeared* to work without problems for a good 15 minutes. private void tickHandler(int id, int msg, int callback, int r1, int r2) { count++; // private ulong holding tick count // now call listeners waiting on the given time period //if (onTimePeriod != null) // onTimePeriod(); } Adding.... { count++; // private ulong holding tick count Console.WriteLine(count); } caused the same problem as mentioned above but after a different number of iterations. It seems to me that the thread is running out of stack/heap space or something or a bad pointer somewhere - but where!? Any ideas what's going wrong and how-to fix it? Thanks! matt. Here's whole class... //******************************************************************* // Based on LP TimerTest // a test application for .NET timers // Copyright: Luc Pattyn, January 2007 // This code is freely available for any non-commercial use. //******************************************************************* using System; using System.Collections; // ArrayList using System.Text; using System.Runtime.InteropServices; // DllImport using System.Threading; namespace Clocks { using TCount = System.Int64; // type to store tick counts using TRes = System.UInt32; // timer resolution public class MSecTimer { public delegate void TimePeriodHandler(); public event TimePeriodHandler onTimePeriod; private int msecTimer; TRes minMSec = 0; TRes maxMSec = 0; private TCount count; private uint interval; private DateTime start; private DateTime stop; public MSecTimer(TRes msecs) { GetCapabilities(); if ((msecs < minMSec) || (msecs > maxMSec)) throw new ArgumentOutOfRangeException("Timer period out of range"); else { interval = msecs; } } private void GetCapabilities() { TimeCaps timeCaps=new TimeCaps(0, 0); uint result=timeGetDevCaps(out timeCaps, Marshal.SizeOf(timeCaps)); if (result!=0) Console.WriteLine("timeGetDevCaps result="+result); minMSec=timeCaps.minimum; maxMSec=timeCaps.maximum; } public void Start() { msecTimer=timeSetEvent(interval, interval, new TimerEventHandler(tickHandler), 0, 1); // type=periodic } public void Stop() { timeKillEvent(msecTimer); } private void tickHandler(int id, int msg, int userCtx, int rsv1, int rsv2) { count++; if (onTimePeriod != null) onTimePeriod(); } [DllImport("Winmm.dll")] private static extern int timeGetTime(); [DllImport("winmm.dll")] private static extern uint timeGetDevCaps(out TimeCaps timeCaps, int size); struct TimeCaps { public uint minimum; public uint maximum; public TimeCaps(uint minimum, uint maximum) { this.minimum=minimum; this.maximum=maximum; } } [DllImport("WinMM.dll", SetLastError=true)] private static extern int timeSetEvent(uint msDelay, uint msResolution, TimerEventHandler handler, int userCtx, int eventType); [DllImport("WinMM.dll", SetLastError=true)] static extern int timeKillEvent(int timerEventId); public delegate void TimerEventHandler(int id, int msg, int userCtx, int rsv1, int rsv2); } } MM wrote:
> I have imported the Multimedia timer funcs from "winmm.dll" These functions are obsolete even in the unmanaged world. Use System.Timers.Timer or System.Threading.Timer instead (not to be confused with System.Windows.Forms.Timer, which uses Window messages and is far less accurate). I'm going to be unhelpful and not diagnose your actual problem, because I get the feeling it's a waste of time. -- J. I have tried those (System.Timers.Timer & System.Threading.Timer) and the
code works without problem. However the problem remains that I've found these solutions just too unpredictable - even using modest time intervals like 1000msecs causes chronic drift particularily when machines under heavy load. I found the multimedia timers to work a treat (barring this annoying problem - see later post). If the funcs in "winmm.dll" are obsolete - what do the multimedia apps use for their timing? Thanks for the advice. Show quoteHide quote "Jeroen Mostert" <jmost***@xs4all.nl> wrote in message news:4a392bd2$0$182$e4fe514c@news.xs4all.nl... > MM wrote: >> I have imported the Multimedia timer funcs from "winmm.dll" > > These functions are obsolete even in the unmanaged world. Use > System.Timers.Timer or System.Threading.Timer instead (not to be confused > with System.Windows.Forms.Timer, which uses Window messages and is far > less accurate). > > I'm going to be unhelpful and not diagnose your actual problem, because I > get the feeling it's a waste of time. > > -- > J. On Wed, 17 Jun 2009 15:00:58 -0700, MM <m*@mm.com> wrote:
> I have tried those (System.Timers.Timer & System.Threading.Timer) and the Unfortunately, they are _not_ obsolete, as Jeroen says. As you've found, > code works without problem. However the problem remains that I've found > these solutions just too unpredictable - even using modest time intervals > like 1000msecs causes chronic drift particularily when machines under > heavy > load. I found the multimedia timers to work a treat (barring this > annoying > problem - see later post). If the funcs in "winmm.dll" are obsolete - > what > do the multimedia apps use for their timing? Thanks for the advice. the multimedia timers are much more precise than any of the thread/message-based timers. It's easy to compensate the regular timers so that over time they produce accurate results, but you'll always have jitter no matter what. If you want that precision, I think winmm.dll is probably the way to go. I think there might be similar timing features in DirectX (DirectSound and/or DirectShow) but off the top of my head I don't have any specifics, and I think winmm.dll is probably going to be easier to use, if _all_ you need is the timer. Unfortunatle Show quoteHide quote > > > > "Jeroen Mostert" <jmost***@xs4all.nl> wrote in message > news:4a392bd2$0$182$e4fe514c@news.xs4all.nl... >> MM wrote: >>> I have imported the Multimedia timer funcs from "winmm.dll" >> >> These functions are obsolete even in the unmanaged world. Use >> System.Timers.Timer or System.Threading.Timer instead (not to be >> confused >> with System.Windows.Forms.Timer, which uses Window messages and is far >> less accurate). >> >> I'm going to be unhelpful and not diagnose your actual problem, because >> I >> get the feeling it's a waste of time. >> >> -- >> J. > > On Wed, 17 Jun 2009 15:00:58 -0700, MM <m*@mm.com> wrote:
> I have tried those (System.Timers.Timer & System.Threading.Timer) and the Unfortunately, they are _not_ obsolete, as Jeroen says. As you've found,> code works without problem. However the problem remains that I've found > these solutions just too unpredictable - even using modest time intervals > like 1000msecs causes chronic drift particularily when machines under > heavy > load. I found the multimedia timers to work a treat (barring this > annoying > problem - see later post). If the funcs in "winmm.dll" are obsolete - > what > do the multimedia apps use for their timing? Thanks for the advice. the multimedia timers are much more precise than any of the thread/message-based timers. It's easy to compensate the regular timers so that over time they produce accurate results, but you'll always have jitter no matter what. If you want that precision, I think winmm.dll is probably the way to go. I think there might be similar timing features in DirectX (DirectSound and/or DirectShow) but off the top of my head I don't have any specifics, and I think winmm.dll is probably going to be easier to use, if _all_ you need is the timer. Sorry to say, I don't actually know enough about p/invoke to know for sure what's causing your exception. But it does seem to me you should be able to get it to work. My usual approach to trying to debug stuff like that is to make absolutely sure I've got it working in unmanaged code first, and then port that over to managed code. Pete Peter Duniho wrote:
Show quoteHide quote > On Wed, 17 Jun 2009 15:00:58 -0700, MM <m*@mm.com> wrote: This is not at all what you'd expect. What versions of Windows are we > >> I have tried those (System.Timers.Timer & System.Threading.Timer) and the >> code works without problem. However the problem remains that I've found >> these solutions just too unpredictable - even using modest time intervals >> like 1000msecs causes chronic drift particularily when machines under >> heavy >> load. I found the multimedia timers to work a treat (barring this >> annoying >> problem - see later post). If the funcs in "winmm.dll" are obsolete - >> what >> do the multimedia apps use for their timing? Thanks for the advice. > > Unfortunately, they are _not_ obsolete, as Jeroen says. As you've found, > the multimedia timers are much more precise than any of the > thread/message-based timers. It's easy to compensate the regular timers > so that over time they produce accurate results, but you'll always have > jitter no matter what. > talking about, anyway? Are we comparing the winmm functions to CreateTimerQueueTimer() or to Threading.Timer (which I've been led to believe is a managed wrapper around the former, on systems that support it)? It seems odd that Microsoft would itself mark functions obsolete that are more accurate than their designated replacements. -- J. On Thu, 18 Jun 2009 10:21:38 -0700, Jeroen Mostert <jmost***@xs4all.nl>
wrote: > This is not at all what you'd expect. What versions of Windows are we I haven't double-checked the implementation of System.Threading.Timer. > talking about, anyway? Are we comparing the winmm functions to > CreateTimerQueueTimer() or to Threading.Timer (which I've been led to > believe is a managed wrapper around the former, on systems that support > it)? It seems odd that Microsoft would itself mark functions obsolete > that are more accurate than their designated replacements. However, a couple of years ago I tried the three .NET timer classes I was aware of (System.Threading.Timer, System.Windows.Forms.Timer, and System.Timers.Timer) and as far as I could tell, they all produced roughly the same behavior. In particular, they all appeared to be subject to thread scheduling issues. I wasn't aware of the newer CreateTimerQueueTimer() function in Windows, but based on my reading of the documentation and my previous experiment, I would say that assuming System.Threading.Timer does use that, it's not passing the settings or flags that would make it a suitable replacement for the multimedia timers. The fact that the OP says he's tried System.Threading.Timer without success suggests that's in fact the case. If you know of a way to get System.Threading.Timer to produce high-precision results, I'm sure the OP would love to know the specifics. Pete Peter Duniho wrote:
Show quoteHide quote > On Thu, 18 Jun 2009 10:21:38 -0700, Jeroen Mostert <jmost***@xs4all.nl> A memory stirs!> wrote: > >> This is not at all what you'd expect. What versions of Windows are we >> talking about, anyway? Are we comparing the winmm functions to >> CreateTimerQueueTimer() or to Threading.Timer (which I've been led to >> believe is a managed wrapper around the former, on systems that >> support it)? It seems odd that Microsoft would itself mark functions >> obsolete that are more accurate than their designated replacements. > > I haven't double-checked the implementation of System.Threading.Timer. > However, a couple of years ago I tried the three .NET timer classes I > was aware of (System.Threading.Timer, System.Windows.Forms.Timer, and > System.Timers.Timer) and as far as I could tell, they all produced > roughly the same behavior. In particular, they all appeared to be > subject to thread scheduling issues. > > I wasn't aware of the newer CreateTimerQueueTimer() function in Windows, > but based on my reading of the documentation and my previous experiment, > I would say that assuming System.Threading.Timer does use that, it's not > passing the settings or flags that would make it a suitable replacement > for the multimedia timers. > Threading.Timer uses .NET's roll-your-own thread pool to dispatch timer events (the one built so that Windows 95 could still run .NET as well). The roll-your-own thread pool is the closest thing there is to an actual native thread pool, except that it isn't one. This confused the hell out of me the first time I learned about it and it still does, because I made the same mistake again, assuming the framework delegated to the obvious native implementation. The roll-your-own thread pool supports timers in the same way the native one does (the same interface and everything), but it *doesn't* use the system's timer queues. It uses its own dedicated timer thread that keeps track of the timers and uses SleepEx() and APCs to wake up at the desired time. This should usually be more accurate than WM_TIMER messages, but it's nowhere near kernel-level accuracy, and obviously preemption is a very real obstacle. I'm very curious as to whether the 4.0 CLR improves any of this (to go along with the framework's own parallel extensions); I've recently installed VS 2010 but haven't checked yet. -- J. MM wrote:
> I have imported the Multimedia timer funcs from "winmm.dll" and setup a c# Here's a little bone to make up for my gaffe earlier about this being > class with the TimerEventHandler:- unnecessary. The following code reduces the scenario to its simplest form and Works On My Machine (tm). Notably it fixes some declarations that had the wrong size on 64-bit machines in your code (in case you use one) and uses a pure delegate instead of events. This suggests any remaining problems may be due to complications introduced by using events (and/or the actual code in the listeners themselves). delegate void TIMECALLBACK(int uTimerID, int uMsg, IntPtr dwUser, IntPtr dw1, IntPtr dw2); static class UnsafeNativeMethods { public const int TIME_ONESHOT = 0; public const int TIME_PERIODIC = 1; public const int TIME_CALLBACK_FUNCTION = 0; public const int TIME_CALLBACK_EVENT_SET = 16; public const int TIME_CALLBACK_EVENT_PULSE = 32; public const int TIME_KILL_SYNCHRONOUS = 0x0100; [DllImport("winmm.dll")] public static extern int timeSetEvent(int uDelay, int uResolution, TIMECALLBACK lpTimeProc, IntPtr dwUser, int fuEvent); [DllImport("winmm.dll")] public static extern int timeKillEvent(int uTimerID); } public sealed class MMTimer : IDisposable { private int timerId; private int tickCount; public int TickCount { get { return tickCount; } } private readonly Action callback; public MMTimer(Action callback, int interval) { this.callback = callback; timerId = UnsafeNativeMethods.timeSetEvent(interval, interval, timeCallback, IntPtr.Zero, UnsafeNativeMethods.TIME_PERIODIC); } private void timeCallback(int uTimerID, int uMsg, IntPtr dwUser, IntPtr dw1, IntPtr dw2) { ++tickCount; callback(); } public void Stop() { ((IDisposable) this).Dispose(); } void IDisposable.Dispose() { if (timerId != 0) UnsafeNativeMethods.timeKillEvent(timerId); GC.SuppressFinalize(this); } ~MMTimer() { Stop(); } } class Program { static void Main(string[] args) { int i = 0; using (MMTimer m = new MMTimer(delegate { Console.WriteLine(++i); }, 10)) { Console.ReadLine(); m.Stop(); Console.WriteLine(m.TickCount); } } } -- J. Hi Jeroen, Thanks for the bone, but here's the thing - your code generates
exactly the same problem as I'm having in my code - AccessViolationException. I changed 1 thing in your code adding a zero param delegate to handle the lamda (marked in the code with ***). With Console.WriteLine in the delegate the code bombs at exactly the same iteration count (9004 on my machine) irrespective of the msec specified. Change the delegate to just "++i" and it runs ad infinitum just as my original code does. I guess the next step is to ascertain whether this behaviour is unique to my machine(s) (I've tried it on 3 running XP/VS2005) or whether it bombs on other one's too. In the meantime, I'll test further. The docs for timeSetEvent makes a reference to avoid System calls in the callback which I wonder if this the problem - if it is I haven't found a way around it - any ideas. A BIG thank-you to both you and Pete for your comments and help. matt. --- CODE --- delegate void TIMECALLBACK(int uTimerID, int uMsg, IntPtr dwUser, IntPtr dw1, IntPtr dw2); static class UnsafeNativeMethods { public const int TIME_ONESHOT = 0; public const int TIME_PERIODIC = 1; public const int TIME_CALLBACK_FUNCTION = 0; public const int TIME_CALLBACK_EVENT_SET = 16; public const int TIME_CALLBACK_EVENT_PULSE = 32; public const int TIME_KILL_SYNCHRONOUS = 0x0100; [DllImport("winmm.dll")] public static extern int timeSetEvent(int uDelay, int uResolution, TIMECALLBACK lpTimeProc, IntPtr dwUser, int fuEvent); [DllImport("winmm.dll")] public static extern int timeKillEvent(int uTimerID); } public sealed class MMTimer : IDisposable { *** // Add a parameterless delegate if not running .NET3.5 else include "using System.Core;" *** publid delegate void Action() private int timerId; private int tickCount; public int TickCount { get { return tickCount; } } private readonly Action callback; public MMTimer(Action callback, int interval) { this.callback = callback; timerId = UnsafeNativeMethods.timeSetEvent(interval, interval, timeCallback, IntPtr.Zero, UnsafeNativeMethods.TIME_PERIODIC); } private void timeCallback(int uTimerID, int uMsg, IntPtr dwUser, IntPtr dw1, IntPtr dw2) { ++tickCount; callback(); } public void Stop() { ((IDisposable) this).Dispose(); } void IDisposable.Dispose() { if (timerId != 0) UnsafeNativeMethods.timeKillEvent(timerId); GC.SuppressFinalize(this); } ~MMTimer() { Stop(); } } class Program { static void Main(string[] args) { int i = 0; using (MMTimer m = new MMTimer(delegate { Console.WriteLine(++i); }, 10)) { Console.ReadLine(); m.Stop(); Console.WriteLine(m.TickCount); } } } -- J.
Other interesting topics
Aren't All MD5 Hashes the Same?
Visual Basic is Dead! Need help in converting the existing patch to c# console application Illegal Instruction Thrown When Executing a Callback Function decorator pattern help VS2008: Format setting for TextEditor will not be applied! VS2005 can't open form validate pdf Linq to sql variable where clause Where exactly the data is stored when we create DataTable |
|||||||||||||||||||||||