Improve multi-threaded code design to prevent race condition - c#

I'm running into an issue that I'm not sure is solvable in the way I want to solve it. I have a problem with a race condition.
I have one project running as a C++ dll (the main engine).
Then I have a second C# process that uses C++/CLI to communicate with the main engine (the editor).
The editor is hosting the engine window as a child window. The result of this is that the child window receives input messages async (see RiProcessMouseMessage()). Normally this only happens when I call window->PollEvents();.
main engine loop {
RiProcessMouseMessage(); // <- Called by the default windows message poll function from the child window
foreach(inputDevice)
inputDevice->UpdateState();
otherCode->UseCurrentInput();
}
The main editor loop is the WPF loop which I don't control. Basically it does this:
main editor loop {
RiProcessMouseMessage(); // <- This one is called by the editor (parent) window, but is using the message loop of the (child) engine window
}
The RawInput processor which is called sync by the engine and async by the editor:
void Win32RawInput::RiProcessMouseMessage(const RAWMOUSE& rmouse, HWND hWnd) {
MouseState& state = Input::mouse._GetGatherState();
// Check Mouse Position Relative Motion
if (rmouse.usFlags == MOUSE_MOVE_RELATIVE) {
vec2f delta((float)rmouse.lLastX, (float)rmouse.lLastY);
delta *= MOUSE_SCALE;
state.movement += delta;
POINT p;
GetCursorPos(&p);
state.cursorPosGlobal = vec2i(p.x, p.y);
ScreenToClient(hWnd, &p);
state.cursorPos = vec2i(p.x, p.y);
}
// Check Mouse Wheel Relative Motion
if (rmouse.usButtonFlags & RI_MOUSE_WHEEL)
state.scrollMovement.y += ((float)(short)rmouse.usButtonData) / WHEEL_DELTA;
if (rmouse.usButtonFlags & RI_MOUSE_HWHEEL)
state.scrollMovement.x += ((float)(short)rmouse.usButtonData) / WHEEL_DELTA;
// Store Mouse Button States
for (int i = 0; i < 5; i++) {
if (rmouse.usButtonFlags & maskDown_[i]) {
state.mouseButtonState[i].pressed = true;
state.mouseButtonState[i].changedThisFrame = true;
} else if (rmouse.usButtonFlags & maskUp_[i]) {
state.mouseButtonState[i].pressed = false;
state.mouseButtonState[i].changedThisFrame = true;
}
}
}
UpdateState() is called only by the engine. It basically swaps the RawInput to the currently used input. This is to prevent input updating in the middle of a frame loop (aka. during otherCode->UseCurrentInput();)
void UpdateState() {
currentState = gatherState; // Copy gather state to current
Reset(gatherState); // Reset the old buffer so the next time the buffer it's used it's all good
// Use current state to check stuff
// For the rest of this frame currentState should be used
}
MouseState& _GetGatherState() { return gatherState; }
void Reset(MouseState& state) { // Might need a lock around gatherState :(
state.movement = vec2f::zero;
state.scrollMovement = vec2f::zero;
for (int i = 0; i < 5; ++i)
state.mouseButtonState[i].changedThisFrame = false;
}
So as you can see the race condition happens when RiProcessMouseMessage() is called while Reset() was called in the main engine loop. If it wasn't clear: The Reset() function is required to reset state back to it's frames default data so that the data is read correctly every frame.
Now I'm very much aware I can fix this easily by adding a mutex around the gatherState updates but I would like to avoid this if possible. Basically I'm asking is it possible to redesign this code to be lock free?

You are asking lock-free which is not quite possible if both ends alter the buffer. But if you ask lock that is optimized and almost instantaneous then you can use FIFO logic. You can use the .net's ConcurrentQueue "https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-5.0" to write updates and poll updates from this queue.
If you really get rid of the lock then you may check lock-free circular arrays aka lock-free ring-buffer,
If you want to dig deeper into hardware level to understand the logic behind this then you can check https://electronics.stackexchange.com/questions/317415/how-to-allow-thread-and-interrupt-safe-writing-of-incoming-usart-data-on-freerto so you will have an idea about concurrency at the low-level as well; With limitations, a lock-free ring buffer can work when one end only writes and the other end only reads within known intervals/boundaries can check similar questions asked:
Circular lock-free buffer
Boost has well-known implementations for lock-free: https://www.boost.org/doc/libs/1_65_1/doc/html/lockfree.html

Related

Repeat Button Tapping

I have a control that allows the user to perform some heavy duty image processing on a specific part of an image and they have arrow buttons to move this area around the image.
as the process is very heavy duty (avg 800ms per run) I have used a repeat button which turns this are into a "Ghost" and only executes the process upon the mouse up event.
This works really well and solves most performance issues relating to this function
HOWEVER
A certain group of users are refusing to learn this method of holding and releasing and persist in tapping the button to move it rather than holding and releasing.
This means that the heavy duty method is being called every time the they tap and as it only moves a small increment each time the method fires, so they end up with a application hang whilst it tries to do > 100 of these 800ms + processes
MY QUESTION
How can I handle this tapping behaviour in the same way as holding and releasing?
I thought about a timer but cant work out how I would detect the difference between a normal tap and the last tap.
Quick, dirty solution: use a Timer.
Each time the user taps the button, stop the timer, increase the number of taps, start the timer. If the timer elapses before the user taps again, then it should do your big work method.
Is this prone to threading issues? Probably. I'm not a threading expert. I would love if a threading expert can come comment on it.
Is this the best solution? Hardly. But it will get you by for a while (until the threading issues come up).
private int _totalTaps = 0;
private const int _tapSequenceThreshold = 250; // Milliseconds
private Timer _tapTimer = new Timer(_tapSequenceThreshold);
private void InitializeTimer()
{
_tapTimer.Elapsed += OnTapTimerElapsed;
}
private void OnTapTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
_tapTimer.Stop();
// The `DoBigLogic` method should take the number of taps and
// then do *something* based on that number, calculate how far
// to move it, for example.
DoBigLogic(_totalTaps);
_totalTaps = 0;
}
// Call this each time the user taps the button
private void Tap()
{
_tapTimer.Stop();
_totalTaps++;
_tapTimer.Start();
}
Best solution: this method plus moving this work off the GUI thread. Then you don't have to worry about taps or click-and-hold, you won't block the GUI thread.
If you have to do work that doesn't update the UI (redraw the image, for example) then send the image to the UI, you can make a new thread, then you'll hit an error about 'accessing a UI element from a non-UI thread', just drop the UI code in a Marshal for it.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { UpdateDisplay(); }
);
Consider monitoring mouse activity and start your heavy duty process after a short period of inactivity.
Consider running the process on a separate thread - this might mean cloning (part of) the image in memory.
Consider preventing the process from being ran multiple times concurrently (if that is possible ie. the process is async).
Consider one of these options:
Disable the button until the process completes, causing that 800ms delay. Users will soon learn to use the hold down method. This would involve the smallest amount of code and put the onus on humans. It also ensures you are not holding up the app with clicks in the buffer or over-using resources.
Put a timer in your button click event:
'Ghost area'
Timer Start ( or reset to zero)
Then the code to call your main work is in the timer elapsed event which will be set to whatever pause you wish. (ie If a user has not clicked again within a second or so)
Then stop the timer
Execute code
You could try using reactive extensions which is available on nuget.
using System;
using System.Windows.Controls;
using System.Windows.Input;
using System.Linq;
using System.Reactive.Linq;
namespace SmoothOutButtonTapping
{
public static class Filters
{
// First we need to combine the pressed events and the released
// events into a single unfiltered stream.
private static IObservable<MouseButtonState> GetUnfilteredStream(Button button)
{
var pressedUnfiltered = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
x => button.PreviewMouseLeftButtonDown += x,
x => button.PreviewMouseLeftButtonDown -= x);
var releasedUnfiltered = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
x => button.PreviewMouseLeftButtonUp += x,
x => button.PreviewMouseLeftButtonUp -= x);
return pressedUnfiltered
.Merge(releasedUnfiltered)
.Select(x => x.EventArgs.ButtonState);
}
// Now we need to apply some filters to the stream of events.
public static IObservable<MouseButtonState> FilterMouseStream(
Button button, TimeSpan slidingTimeoutWindow)
{
var unfiltered = GetUnfilteredStream(button);
// Ironically, we have to separate the pressed and released events, even
// though we just combined them.
// This is because we need to apply a filter to throttle the released events,
// but we don't need to apply any filters to the pressed events.
var released = unfiltered
// Here we throttle the events so that we don't get a released event
// unless the button has been released for a bit.
.Throttle(slidingTimeoutWindow)
.Where(x => x == MouseButtonState.Released);
var pressed = unfiltered
.Where(x => x == MouseButtonState.Pressed);
// Now we combine the throttled stream of released events with the unmodified
// stream of pressed events.
return released.Merge(pressed);
}
}
}
Now we have a stream that will respond immediately whenever a user presses, but will not fire a released event unless the button is released for long enough.
Here is an example of how you could consume the above method. This example simply changes the color of the control while the button is in the Pressed state, but you could easily do whatever you wanted.
using System;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Reactive.Linq;
using System.Threading;
namespace SmoothOutButtonTapping
{
public partial class SmoothTapButtonControl : UserControl
{
public SmoothTapButtonControl()
{
InitializeComponent();
_pressed = new SolidColorBrush(Colors.Lime);
_released = Background;
// Don't forget to call ObserveOn() to ensure your UI controls
// only get accessed from the UI thread.
Filters.FilterMouseStream(button, SlidingTimeoutWindow)
.ObserveOn(SynchronizationContext.Current)
.Subscribe(HandleClicked);
}
// This property indicates how long the button must wait before
// responding to being released.
// If the button is pressed again before this timeout window
// expires, it resets.
// This is handled for us automatically by Reactive Extensions.
public TimeSpan SlidingTimeoutWindow { get; set; } = TimeSpan.FromSeconds(.4);
private void HandleClicked(MouseButtonState state)
{
if (state == MouseButtonState.Pressed)
Background = _pressed;
else
Background = _released;
}
private Brush _pressed;
private Brush _released;
}
}
You can find the complete version of the above examples (project files and xaml included) on my github.
You can prevent program from executing your 800 ms function by setting simple flags(Preferably bool type).
You need to create three events. One Mouse Down, one Mouse Up event and other is Mouse Move event of the button. Set your flag false at declaration. When you click the button, make your flag true in Mouse Down event. And when you lift your mouse click i.e., Mouse Up event make your flag false.
Simple illustration of code.
bool click = false,run_process = true;
mouseDown_event()
{
click = true;
}
mouseUp_event()
{
click = false;
}
mouseMove_event()
{
if(click == true && run_process == true)
{
click = false;
run_process = false;
//call your function
}
}
How can I handle this tapping behaviour in the same way as holding and releasing?
Create a formula which calculates a weight value based last tap frequency, current operation and time between last actual operation; with any other factors I may not be aware of. With the right formula it should be representational to the person who uses the system correctly verses someone who sends multiple clicks.
The weighted value should be passed to an alternate thread which is handling the actual operation to the screen and can handle a blizzard of taps or a single tap without missing a beat, per se.

CPU-greedy loop when streaming music

To give some context, I'm working on an opensource alternative desktop Spotify client, with accessibility at it's core. You'll also see some NAudio in here.
I'm noticing pretty intense CPU usage as soon as playback starts. Even when paused, the CPU is high.
I ran Visual Studio's inbuilt profiler to try and shed some light on any resource hogs that might be occuring. As I suspected, the problem wasin my playback manager's streaming loop.
The code that the profiler flags as one of the most sample-rich is as follows:
const int secondsToBuffer = 3;
private void GetStreaming(object state)
{
this.fullyDownloaded = false;
// secondsToBuffer is an integer to represent how many seconds we should buffer up at once to prevent choppy playback on slow connections
try
{
do
{
if (bufferedWaveProvider == null)
{
this.bufferedWaveProvider = new BufferedWaveProvider(new WaveFormat(44100, 2));
this.bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves
Logger.WriteDebug("Creating buffered wave provider");
this.gatekeeper.MinimumSampleSize = bufferedWaveProvider.WaveFormat.AverageBytesPerSecond * secondsToBuffer;
}
// this bit in particular seems to be the hot point
if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Logger.WriteDebug("Buffer getting full, taking a break");
Thread.Sleep(500);
}
// do we have at least double the buffered sample's size in free space, just in case
else if (bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes > bufferedWaveProvider.WaveFormat.AverageBytesPerSecond * (secondsToBuffer * 2))
{
var sample = gatekeeper.Read();
if (sample != null)
{
bufferedWaveProvider.AddSamples(sample, 0, sample.Length);
}
}
} while (playbackState != StreamingPlaybackState.Stopped);
Logger.WriteDebug("Playback stopped");
}
finally
{
// no post-processing work here, right?
}
}
An NAudio sample was the inspiration for my way of handling streaming in this method. To find the full file's source code, you can view it here: http://blindspot.codeplex.com/SourceControl/latest#Blindspot.Playback/PlaybackManager.cs
I'm a newbie to profiling and I'm not a year on year expert on streaming either (both might be obvious).
Is there any way I can make this loop less resource intensive. Would increasing the sleep amount in the if block where the buffer is full help? Or am I barking up the wrong tree here. It seems like it would, but I'd have thought half a second would be sufficient.
Any help gratefully received.
Basically, you've created an infinite loop until the buffer gets full. The section you've marked with
// this bit in particular seems to be the hot point
probably appears to be as the calculations in the if statement are just being repeated over and over again; can any of them be moved outside of the loop?
I'd put a Thread.Sleep(50) before the while statement to prevent thrashing and see if that makes a difference (I suspect it will).

Why is my C# program faster in a profiler?

I have a relatively large system (~25000 lines so far) for monitoring radio-related devices. It shows graphs and such using latest version of ZedGraph.
The program is coded using C# on VS2010 with Win7.
The problem is:
when I run the program from within VS, it runs slow
when I run the program from the built EXE, it runs slow
when I run the program though Performance Wizard / CPU Profiler, it runs Blazing Fast.
when I run the program from the built EXE, and then start VS and Attach a profiler to ANY OTHER PROCESS, my program speeds up!
I want the program to always run that fast!
Every project in the solution is set to RELEASE, Debug unmanaged code is DISABLED, Define DEBUG and TRACE constants is DISABLED, Optimize Code - I tried either, Warning Level - I tried either, Suppress JIT - I tried either,
in short I tried all the solutions already proposed on StackOverflow - none worked. Program is slow outside profiler, fast in profiler.
I don't think the problem is in my code, because it becomes fast if I attach the profiler to other, unrelated process as well!
Please help!
I really need it to be that fast everywhere, because it's a business critical application and performance issues are not tolerated...
UPDATES 1 - 8 follow
--------------------Update1:--------------------
The problem seems to Not be ZedGraph related, because it still manifests after I replaced ZedGraph with my own basic drawing.
--------------------Update2:--------------------
Running the program in a Virtual machine, the program still runs slow, and running profiler from the Host machine doesn't make it fast.
--------------------Update3:--------------------
Starting screen capture to video also speeds the program up!
--------------------Update4:--------------------
If I open the Intel graphics driver settings window (this thing: http://www.intel.com/support/graphics/sb/img/resolution_new.jpg)
and just constantly hover with the cursor over buttons, so they glow, etc, my program speeds up!.
It doesn't speed up if I run GPUz or Kombustor though, so no downclocking on the GPU - it stays steady 850Mhz.
--------------------Update5:--------------------
Tests on different machines:
-On my Core i5-2400S with Intel HD2000, UI runs slow and CPU usage is ~15%.
-On a colleague's Core 2 Duo with Intel G41 Express, UI runs fast, but CPU usage is ~90% (which isn't normal either)
-On Core i5-2400S with dedicated Radeon X1650, UI runs blazing fast, CPU usage is ~50%.
--------------------Update6:--------------------
A snip of code showing how I update a single graph (graphFFT is an encapsulation of ZedGraphControl for ease of use):
public void LoopDataRefresh() //executes in a new thread
{
while (true)
{
while (!d.Connected)
Thread.Sleep(1000);
if (IsDisposed)
return;
//... other graphs update here
if (signalNewFFT && PanelFFT.Visible)
{
signalNewFFT = false;
#region FFT
bool newRange = false;
if (graphFFT.MaxY != d.fftRangeYMax)
{
graphFFT.MaxY = d.fftRangeYMax;
newRange = true;
}
if (graphFFT.MinY != d.fftRangeYMin)
{
graphFFT.MinY = d.fftRangeYMin;
newRange = true;
}
List<PointF> points = new List<PointF>(2048);
int tempLength = 0;
short[] tempData = new short[2048];
int i = 0;
lock (d.fftDataLock)
{
tempLength = d.fftLength;
tempData = (short[])d.fftData.Clone();
}
foreach (short s in tempData)
points.Add(new PointF(i++, s));
graphFFT.SetLine("FFT", points);
if (newRange)
graphFFT.RefreshGraphComplete();
else if (PanelFFT.Visible)
graphFFT.RefreshGraph();
#endregion
}
//... other graphs update here
Thread.Sleep(5);
}
}
SetLine is:
public void SetLine(String lineTitle, List<PointF> values)
{
IPointListEdit ip = zgcGraph.GraphPane.CurveList[lineTitle].Points as IPointListEdit;
int tmp = Math.Min(ip.Count, values.Count);
int i = 0;
while(i < tmp)
{
if (values[i].X > peakX)
peakX = values[i].X;
if (values[i].Y > peakY)
peakY = values[i].Y;
ip[i].X = values[i].X;
ip[i].Y = values[i].Y;
i++;
}
while(ip.Count < values.Count)
{
if (values[i].X > peakX)
peakX = values[i].X;
if (values[i].Y > peakY)
peakY = values[i].Y;
ip.Add(values[i].X, values[i].Y);
i++;
}
while(values.Count > ip.Count)
{
ip.RemoveAt(ip.Count - 1);
}
}
RefreshGraph is:
public void RefreshGraph()
{
if (!explicidX && autoScrollFlag)
{
zgcGraph.GraphPane.XAxis.Scale.Max = Math.Max(peakX + grace.X, rangeX);
zgcGraph.GraphPane.XAxis.Scale.Min = zgcGraph.GraphPane.XAxis.Scale.Max - rangeX;
}
if (!explicidY)
{
zgcGraph.GraphPane.YAxis.Scale.Max = Math.Max(peakY + grace.Y, maxY);
zgcGraph.GraphPane.YAxis.Scale.Min = minY;
}
zgcGraph.Refresh();
}
.
--------------------Update7:--------------------
Just ran it through the ANTS profiler. It tells me that the ZedGraph refresh counts when the program is fast are precisely two times higher compared to when it's slow.
Here are the screenshots:
I find it VERY strange that, considering the small difference in the length of the sections, performance differs twice with mathematical precision.
Also, I updated the GPU driver, that didn't help.
--------------------Update8:--------------------
Unfortunately, for a few days now, I'm unable to reproduce the issue... I'm getting constant acceptable speed (which still appear a bit slower than what I had in the profiler two weeks ago) which isn't affected by any of the factors that used to affect it two weeks ago - profiler, video capturing or GPU driver window. I still have no explanation of what was causing it...
Luaan posted the solution in the comments above, it's the system wide timer resolution. Default resolution is 15.6 ms, the profiler sets the resolution to 1ms.
I had the exact same problem, very slow execution that would speed up when the profiler was opened. The problem went away on my PC but popped back up on other PCs seemingly at random. We also noticed the problem disappeared when running a Join Me window in Chrome.
My application transmits a file over a CAN bus. The app loads a CAN message with eight bytes of data, transmits it and waits for an acknowledgment. With the timer set to 15.6ms each round trip took exactly 15.6ms and the entire file transfer would take about 14 minutes. With the timer set to 1ms round trip time varied but would be as low as 4ms and the entire transfer time would drop to less than two minutes.
You can verify your system timer resolution as well as find out which program increased the resolution by opening a command prompt as administrator and entering:
powercfg -energy duration 5
The output file will have the following in it somewhere:
Platform Timer Resolution:Platform Timer Resolution
The default platform timer resolution is 15.6ms (15625000ns) and should be used whenever the system is idle. If the timer resolution is increased, processor power management technologies may not be effective. The timer resolution may be increased due to multimedia playback or graphical animations.
Current Timer Resolution (100ns units) 10000
Maximum Timer Period (100ns units) 156001
My current resolution is 1 ms (10,000 units of 100nS) and is followed by a list of the programs that requested the increased resolution.
This information as well as more detail can be found here: https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/
Here is some code to increase the timer resolution (originally posted as the answer to this question: how to set timer resolution from C# to 1 ms?):
public static class WinApi
{
/// <summary>TimeBeginPeriod(). See the Windows API documentation for details.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
/// <summary>TimeEndPeriod(). See the Windows API documentation for details.</summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
public static extern uint TimeEndPeriod(uint uMilliseconds);
}
Use it like this to increase resolution :WinApi.TimeBeginPeriod(1);
And like this to return to the default :WinApi.TimeEndPeriod(1);
The parameter passed to TimeEndPeriod() must match the parameter that was passed to TimeBeginPeriod().
There are situations when slowing down a thread can speed up other threads significantly, usually when one thread is polling or locking some common resource frequently.
For instance (this is a windows-forms example) when the main thread is checking overall progress in a tight loop instead of using a timer, for example:
private void SomeWork() {
// start the worker thread here
while(!PollDone()) {
progressBar1.Value = PollProgress();
Application.DoEvents(); // keep the GUI responisive
}
}
Slowing it down could improve performance:
private void SomeWork() {
// start the worker thread here
while(!PollDone()) {
progressBar1.Value = PollProgress();
System.Threading.Thread.Sleep(300); // give the polled thread some time to work instead of responding to your poll
Application.DoEvents(); // keep the GUI responisive
}
}
Doing it correctly, one should avoid using the DoEvents call alltogether:
private Timer tim = new Timer(){ Interval=300 };
private void SomeWork() {
// start the worker thread here
tim.Tick += tim_Tick;
tim.Start();
}
private void tim_Tick(object sender, EventArgs e){
tim.Enabled = false; // prevent timer messages from piling up
if(PollDone()){
tim.Tick -= tim_Tick;
return;
}
progressBar1.Value = PollProgress();
tim.Enabled = true;
}
Calling Application.DoEvents() can potentially cause allot of headaches when GUI stuff has not been disabled and the user kicks off other events or the same event a 2nd time simultaneously, causing stack climbs which by nature queue the first action behind the new one, but I'm going off topic.
Probably that example is too winforms specific, I'll try making a more general example. If you have a thread that is filling a buffer that is processed by other threads, be sure to leave some System.Threading.Thread.Sleep() slack in the loop to allow the other threads to do some processing before checking if the buffer needs to be filled again:
public class WorkItem {
// populate with something usefull
}
public static object WorkItemsSyncRoot = new object();
public static Queue<WorkItem> workitems = new Queue<WorkItem>();
public void FillBuffer() {
while(!done) {
lock(WorkItemsSyncRoot) {
if(workitems.Count < 30) {
workitems.Enqueue(new WorkItem(/* load a file or something */ ));
}
}
}
}
The worker thread's will have difficulty to obtain anything from the queue since its constantly being locked by the filling thread. Adding a Sleep() (outside the lock) could significantly speed up other threads:
public void FillBuffer() {
while(!done) {
lock(WorkItemsSyncRoot) {
if(workitems.Count < 30) {
workitems.Enqueue(new WorkItem(/* load a file or something */ ));
}
}
System.Threading.Thread.Sleep(50);
}
}
Hooking up a profiler could in some cases have the same effect as the sleep function.
I'm not sure if I've given representative examples (it's quite hard to come up with something simple) but I guess the point is clear, putting sleep() in the correct place can help improve the flow of other threads.
---------- Edit after Update7 -------------
I'd remove that LoopDataRefresh() thread altogether. Rather put a timer in your window with an interval of at least 20 (which would be 50 frames a second if none were skipped):
private void tim_Tick(object sender, EventArgs e) {
tim.Enabled = false; // skip frames that come while we're still drawing
if(IsDisposed) {
tim.Tick -= tim_Tick;
return;
}
// Your code follows, I've tried to optimize it here and there, but no guarantee that it compiles or works, not tested at all
if(signalNewFFT && PanelFFT.Visible) {
signalNewFFT = false;
#region FFT
bool newRange = false;
if(graphFFT.MaxY != d.fftRangeYMax) {
graphFFT.MaxY = d.fftRangeYMax;
newRange = true;
}
if(graphFFT.MinY != d.fftRangeYMin) {
graphFFT.MinY = d.fftRangeYMin;
newRange = true;
}
int tempLength = 0;
short[] tempData;
int i = 0;
lock(d.fftDataLock) {
tempLength = d.fftLength;
tempData = (short[])d.fftData.Clone();
}
graphFFT.SetLine("FFT", tempData);
if(newRange) graphFFT.RefreshGraphComplete();
else if(PanelFFT.Visible) graphFFT.RefreshGraph();
#endregion
// End of your code
tim.Enabled = true; // Drawing is done, allow new frames to come in.
}
}
Here's the optimized SetLine() which no longer takes a list of points but the raw data:
public class GraphFFT {
public void SetLine(String lineTitle, short[] values) {
IPointListEdit ip = zgcGraph.GraphPane.CurveList[lineTitle].Points as IPointListEdit;
int tmp = Math.Min(ip.Count, values.Length);
int i = 0;
peakX = values.Length;
while(i < tmp) {
if(values[i] > peakY) peakY = values[i];
ip[i].X = i;
ip[i].Y = values[i];
i++;
}
while(ip.Count < values.Count) {
if(values[i] > peakY) peakY = values[i];
ip.Add(i, values[i]);
i++;
}
while(values.Count > ip.Count) {
ip.RemoveAt(ip.Count - 1);
}
}
}
I hope you get that working, as I commented before, I hav'nt got the chance to compile or check it so there could be some bugs there. There's more to be optimized there, but the optimizations should be marginal compared to the boost of skipping frames and only collecting data when we have the time to actually draw the frame before the next one comes in.
If you closely study the graphs in the video at iZotope, you'll notice that they too are skipping frames, and sometimes are a bit jumpy. That's not bad at all, it's a trade-off you make between the processing power of the foreground thread and the background workers.
If you really want the drawing to be done in a separate thread, you'll have to draw the graph to a bitmap (calling Draw() and passing the bitmaps device context). Then pass the bitmap on to the main thread and have it update. That way you do lose the convenience of the designer and property grid in your IDE, but you can make use of otherwise vacant processor cores.
---------- edit answer to remarks --------
Yes there is a way to tell what calls what. Look at your first screen-shot, you have selected the "call tree" graph. Each next line jumps in a bit (it's a tree-view, not just a list!). In a call-graph, each tree-node represents a method that has been called by its parent tree-node (method).
In the first image, WndProc was called about 1800 times, it handled 872 messages of which 62 triggered ZedGraphControl.OnPaint() (which in turn accounts for 53% of the main threads total time).
The reason you don't see another rootnode, is because the 3rd dropdown box has selected "[604] Mian Thread" which I didn't notice before.
As for the more fluent graphs, I have 2nd thoughts on that now after looking more closely to the screen-shots. The main thread has clearly received more (double) update messages, and the CPU still has some headroom.
It looks like the threads are out-of-sync and in-sync at different times, where the update messages arrive just too late (when WndProc was done and went to sleep for a while), and then suddenly in time for a while. I'm not very familiar with Ants, but does it have a side-by side thread timeline including sleep time? You should be able to see what's going on in such a view. Microsofts threads view tool would come in handy for this:
When I have never heard or seen something similar; I’d recommend the common sense approach of commenting out sections of code/injecting returns at tops of functions until you find the logic that’s producing the side effect. You know your code and likely have an educated guess where to start chopping. Else chop mostly all as a sanity test and start adding blocks back. I’m often amazed how fast one can find those seemingly impossible bugs to track. Once you find the related code, you will have more clues to solve your issue.
There is an array of potential causes. Without stating completeness, here is how you could approach your search for the actual cause:
Environment variables: the timer issue in another answer is only one example. There might be modifications to the Path and to other variables, new variables could be set by the profiler. Write the current environment variables to a file and compare both configurations. Try to find suspicious entries, unset them one by one (or in combinations) until you get the same behavior in both cases.
Processor frequency. This can easily happen on laptops. Potentially, the energy saving system sets the frequency of the processor(s) to a lower value to save energy. Some apps may 'wake' the system up, increasing the frequency. Check this via performance monitor (permon).
If the apps runs slower than possible there must be some inefficient resource utilization. Use the profiler to investigate this! You can attache the profiler to the (slow) running process to see which resources are under-/ over-utilized. Mostly, there are two major categories of causes for too slow execution: memory bound and compute bound execution. Both can give more insight into what is triggering the slow-down.
If, however, your app actually changes its efficiency by attaching to a profiler you can still use your favorite monitor app to see, which performance indicators do actually change. Again, perfmon is your friend.
If you have a method which throws a lot of exceptions, it can run slowly in debug mode and fast in CPU Profiling mode.
As detailed here, debug performance can be improved by using the DebuggerNonUserCode attribute. For example:
[DebuggerNonUserCode]
public static bool IsArchive(string filename)
{
bool result = false;
try
{
//this calls an external library, which throws an exception if the file is not an archive
result = ExternalLibrary.IsArchive(filename);
}
catch
{
}
return result;
}

Is there any way I can integrate the MS Office Smooth Typing in a C# application?

In my opinion the MS Office Smooth Typing is a very innovative feature in the Office Suite, and I'd like to know if this feature is available for programmers in the .NET Framework, specifically in the C# language.
If so, could you please post in your answer a usage example and link to the documentation?
Thanks.
By "smooth typing" I'm referring to the typing animation, that makes the cursor slide during typing.
I don't own Office, so I can't look at the feature, but I needed to fiddle around with the caret in RichTextBoxes a while ago and decided that it wasn't worth the effort. Basically you are on your own. No helper functions from .NET, but everything is handled by the backing Win32 control. You will have a hard time defeating what already happens under the hood. And probably ending up intercepting window messages and lots of ugly code.
So my basic advice is: Don't do it. At least for basic form controls like the TextBox or RichTextBox. You may have more luck trying to remote access an running office from within .NET, but that is a totally different can of worms.
If you really insist on going the SetCaretPos - route, here is some code to get you up and running with a basic version where you can improve upon:
// import the functions (which are part of Win32 API - not .NET)
[DllImport("user32.dll")] static extern bool SetCaretPos(int x, int y);
[DllImport("user32.dll")] static extern Point GetCaretPos(out Point point);
public Form1()
{
InitializeComponent();
// target position to animate towards
Point targetCaretPos; GetCaretPos(out targetCaretPos);
// richTextBox1 is some RichTextBox that I dragged on the form in the Designer
richTextBox1.TextChanged += (s, e) =>
{
// we need to capture the new position and restore to the old one
Point temp;
GetCaretPos(out temp);
SetCaretPos(targetCaretPos.X, targetCaretPos.Y);
targetCaretPos = temp;
};
// Spawn a new thread that animates toward the new target position.
Thread t = new Thread(() =>
{
Point current = targetCaretPos; // current is the actual position within the current animation
while (true)
{
if (current != targetCaretPos)
{
// The "30" is just some number to have a boundary when not animating
// (e.g. when pressing enter). You can experiment with your own distances..
if (Math.Abs(current.X - targetCaretPos.X) + Math.Abs(current.Y - targetCaretPos.Y) > 30)
current = targetCaretPos; // target too far. Just move there immediately
else
{
current.X += Math.Sign(targetCaretPos.X - current.X);
current.Y += Math.Sign(targetCaretPos.Y - current.Y);
}
// you need to invoke SetCaretPos on the thread which created the control!
richTextBox1.Invoke((Action)(() => SetCaretPos(current.X, current.Y)));
}
// 7 is just some number I liked. The more, the slower.
Thread.Sleep(7);
}
});
t.IsBackground = true; // The animation thread won't prevent the application from exiting.
t.Start();
}
Use SetCaretPos with your own animation timing function. Create a new thread that interpolates the caret's position based on the previous location and the new desired location.

C#/Winforms App freezing/lagging

I have an Application in C#/Winforms that is basically used to run test for customers accounts in a specific order/setup. They are all tests run in browsers and so I built it so it would automate the process since there are about 10-12 tests that need to be ran everytime a customer account is pulled up.
Basically what happens is you input the account number then it runs the tests.
Here's a sample code.
public void startTestProcess()
{
if (!cancelTests)
{
testRunning = true;
var tabPage = createTabPage(banToRun, Convert.ToInt32(banToRun));
loadingBox.Visible = true;
mainTabControl.TabPages.Insert(0, tabPage);
mainTabControl.SelectedTab = mainTabControl.TabPages[0];
runTest(tabPage, banToRun);
loadingBox.Visible = false;
}
}
private void runTest(TabPage t, string ban)
{
if (!cancelTests && !cancelCurrentOnly)
{
var tC = createInitialTabControl();
t.Controls.Add(tC);
int[] theTests = profileInfo.getSetList;
for (int i = 0; i < theTests.Length; i++)
{
if (!cancelTests && !cancelCurrentOnly)
{
var newTab = createTabPage(urlStrings.getName(theTests[i]), theTests[i]);
tC.TabPages.Add(newTab);
var webBrowser = createBrowser(urlStrings.getUrl(theTests[i], ban));
newTab.Controls.Add(webBrowser);
if (theTests[i] != 0 && theTests[i] != 1 && theTests[i] != 6
&& theTests[i] != 11 && theTests[i] != 12)
{
if (!webBrowser.IsDisposed)
{
try
{
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
}
catch
{
//Do Nothing
}
}
}
IntPtr pHandle = GetCurrentProcess();
SetProcessWorkingSetSize(pHandle, -1, -1);
}
}
}
if (cancelCurrentOnly)
{
cancelCurrentOnly = false;
}
banToRun = string.Empty;
testRunning = false;
}
So basically my question is, how can I optimize what I have in order to
A. Reduce lag/freezing - Note: Already implemented a way of forcing garbage collection after each test is run.
B. Improve performance of the WebBrowser controls possibly? - Already tried some webbrowser alternatives like WebKit for C# Wrapper (does not work on all tests due to some ajax based coding i believe)
C. Maybe implement multi-threaded operations. Not sure how i'd go about this without having cross-threaded exceptions thrown.
Thanks for your assistance. If you have any other questions feel free to ask.
The lag / freezing issue is caused by you not using multiple threads; therefore all of the test runs are using the UI thread, so the UI cannot respond while the tests are being run.
If the reason you are not using a backround worker(s) is that your are worried about having cross-threaded exceptions thrown, then you just need to make sure you are properly passing information between your threads (as opposed to avoiding multithreading altogether).
Update
This question addresses the issue of updating the UI based on workers' progress.
As a side note, you should not have to force garbage collection; most of the time, this will actually decrease performance. The garbage collector is specifically designed to collect when it has availability to do so (when the CPU is available). Forcing it to run takes cycles away from the real work your app is trying to do.
I see a lot of heavy lifting being performed in methods that also handle GUI, and therefore I assume that all of this is being done in the application's main thread (which will block while performing non-graphic operations related to that WebBrowser and other areas).
Try to refactor this application to run in multiple threads. The main thread should be available as much as possible to respond to user events. Background threads should do the heavy lifting of creating expensive objects, performing long-running read/write operations, etc.

Categories

Resources