im new here and always find helpful threads here, but not in this case. I'm having an issue with my program using threads. In special, my thread is doing some image pattern in the backround and everything seems to be fine.
It also works an undefined time (sometimes 15 s, sometimes minutes) without any exception or freeze or whatever. But then my GUI freezes, not my whole GUI, just the GUI parts updated from the thread. Two other pictureboxes are working fine(streaming a video), but the rest isnt working.
Trying to stop the thread where it is, works, but starting it from there makes my program collapse.
There arn't eny exceptions thrown. Every GUI element is updated via Invoke() if necessary. I only work on a copy of the Picture to avoid any lockmodes or anything else. Also i try to let the UI doing what it needs to do (DoEvents())
Some ideas?
Code:
namespace My.Name.Space
{
public class MyThread : MyThreadBase
{
public MyThread ( getting object s from the form for updating UI elements)
{
//referencing objects
Stopwatch.Start();
}
//example Method for UI updating
private void UpdateRobot1Box(int angle, int x, int y)
{
if (_rob1.InvokeRequired)
{
_rob1.Invoke(new Action(() => _rob1.Clear()));
_rob1.Invoke(new Action(() => _rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString()));
}
else
{
_rob1.Clear();
_rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString();
}
}
protected override void Loop(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
if( PictureBox != null && Stopwatch.ElapsedMilliseconds >= tick)
{
//DoWork
Application.DoEvents();
}
else
{
Thread.Sleep(1);
}
}
}
}
}
}
Edit 1:
MyThreadBase:
namespace My.Name.Space
{
public abstract class MyThreadBase : DisposableBase//just some simple gc stuff
{
private CancellationTokenSource _cancellationTokenSource;
public bool IsAlive
{
get { return _cancellationTokenSource != null; }
}
public event Action<Object, Exception> UnhandledException;
public void Start()
{
if (_cancellationTokenSource != null)
return;
lock (this)
{
if (_cancellationTokenSource != null)
return;
_cancellationTokenSource = new CancellationTokenSource();
var thread = new Thread(RunLoop) {Name = GetType().Name};
thread.Start();
}
}
public void Stop()
{
if (_cancellationTokenSource == null)
return;
lock (this)
{
if (_cancellationTokenSource == null)
return;
_cancellationTokenSource.Cancel();
}
}
public void Join()
{
while (IsAlive) Thread.Sleep(1);
}
private void RunLoop()
{
try
{
CancellationToken token = _cancellationTokenSource.Token;
Loop(token);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception)
{
OnException(exception);
}
finally
{
lock (this)
{
CancellationTokenSource cancellationTokenSource = _cancellationTokenSource;
_cancellationTokenSource = null;
cancellationTokenSource.Dispose();
}
}
}
protected abstract void Loop(CancellationToken token);
protected virtual void OnException(Exception exception)
{
Trace.TraceError("{0} - Exception: {1}", GetType(), exception.Message);
Trace.TraceError(exception.StackTrace);
OnUnhandledException(exception);
}
protected virtual void OnUnhandledException(Exception exception)
{
if (UnhandledException != null)
UnhandledException(this, exception);
}
protected override void DisposeOverride()
{
Stop();
}
}
The UpdateRobot1Box is called in a switch-case construct within the thread. I got a little for-squence where I go through my list of own created objects to decide what to write in my textbox.
Create a method in main form class to perform the UI update actions:
private void AsyncFormUpdate(Action action)
{
if (this.InvokeRequired)
{
this.Invoke(action, null);
}
else
{
action();
}
}
Having that in proper place you are sure that InvokeRequired acts properly, well, and the code is better encapsulated.
Next be simple. Use the asynchronously invoked delegate with feedback to report angle and coordinates changes to UI, where you'll actually call the AsyncFormUpdate method.
A good example is shown here:
http://www.csharp-examples.net/asynchronous-method-progress/
There they update the progress, where as you'll update the angle and X/Y coordinates.
Related
I have a class that populates 1000 ComboBoxes into the UI, the code is
namespace ActiveXMemory
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PopulateControls();
}
public void PopulateControls() {
var newGrid = new Grid();
for (var i = 0; i < 1000; i++)
{
ComboBox newcombo = new ComboBox();
newGrid.Children.Add(newcombo);
}
this.Content = newGrid;
}
public bool OpenWindow(bool isRunning)
{
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
try
{
this.ShowDialog();
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
}));
return true;
}
public bool CloseWindow()
{
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
try
{
this.Close();
}
catch (Exception exp)
{
//Console.WriteLine(exp.Message);
}
}));
return true;
}
private void Window_Closed(object sender, EventArgs e)
{
var grid = Content as Grid;
var children = grid.Children;
while (children.Count > 0)
{
var child = children[0];
grid.Children.Remove(child);
child = null;
}
grid = null;
}
}
}
I created an ActiveX library for the class to be accessible as ActiveX,
namespace ActiveXLibrary
{
[ComVisible(true)]
[Guid("EF2EAD91-68A8-420D-B5C9-E30A6F510BDE")]
public interface IActiveXLib
{
[DispId(1)]
bool Initialize();
[DispId(2)]
bool CloseActiveX();
}
[ComVisible(true)]
[Guid("9DACD44F-0237-4F44-BCB9-0E6B729915D6"),
ClassInterface(ClassInterfaceType.None)]
[ProgId("Samp")]
public class ActiveXLib : IActiveXLib
{
MainWindow form;
Thread thr;
public bool Initialize()
{
int i = 0;
try
{
ThreadStart exeFunc = new ThreadStart(() =>
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Send, new Action(() =>
{
start();
}));
});
thr = new Thread(exeFunc);
thr.SetApartmentState(ApartmentState.STA);
thr.Start();
while (form == null)
{
i++;
//Console.WriteLine("form Null");
System.Threading.Thread.Sleep(1000);
if (i > 30)
break;
}
return true;
}
catch (Exception exp)
{
Console.WriteLine("[Initialize]" + exp.Message);
return false;
}
}
public bool CloseActiveX()
{
bool success = false;
try
{
success = form.CloseWindow();
form = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
return success;
}
catch (Exception exp)
{
Console.WriteLine("[CloseActiveX]" + exp.Message);
return false;
}
}
private void start()
{
try
{
Console.WriteLine("start() - new MainWindow()");
form = new MainWindow();
Console.WriteLine("OpenWindow()");
form.OpenWindow(true);
}
catch (Exception exp)
{
MessageBox.Show(exp.Message + "\nPossible Reasons: " + exp.Source + "\n" + exp.InnerException, "Error");
}
}
}
}
Then I created a demo project as
ActiveXLib activeXRef;
public MainWindow()
{
InitializeComponent();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
activeXRef = new ActiveXLib();
activeXRef.Initialize();
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
activeXRef.CloseActiveX();
GC.Collect();
}
Here the problem is every time I click the start and stop button, the memory keeps on increasing, the memory (17MB) created by the first start of the application did not get released, even though I removed the ComboBoxes and set the grid content null. Even the GC.Collect() has no effect, since it only adds the garbage to a queue. Is there any fix for this.
I also tried flushing the memory as in the link, But even then the memory is still held.(since I am not sure whether the handle of the current process is from demo project/from ActiveXMemory)
Edit
I included the line
this.Dispatcher.Invoke(DispatcherPriority.Render, GCDelegate);
to the Window_Closed event
Now the memory gets cleared
But one problem I am facing now is, if I try to immediately close (call CloseActiveX()), then this is not happening.(i.e)
private void startButton_Click(object sender, RoutedEventArgs e)
{
activeXRef = new ActiveXLib();
activeXRef.Initialize();
activeXRef.CloseActiveX();
activeXRef = null;
GC.Collect();
}
The above code still has the memory locked, I don't understand the difference, it is just another event,Does anyone have any idea on this?
I think I got a repro for this problem although I can't tell what your MainWindow.Open/CloseWindow() methods look like. Using a thread is certainly part of the problem, there is one non-intuitive thing you have to do to prevent leaking internal WPF plumbing objects that have thread affinity.
It is imperative to shutdown the dispatcher for the thread. This normally just happens once in a WPF app when the UI thread terminates. Also very important that the dispatcher does the dispatching, WPF heavily depends on it to ensure that "weak events" are actually weak.
A sample implementation for MainWindow that does not leak:
public class MainWindow : Window {
public void OpenWindow(bool noidea) {
this.ShowDialog();
}
public bool CloseWindow() {
this.Dispatcher.Invoke(() => {
this.Dispatcher.InvokeShutdown(); // <== Important!
});
return true;
}
}
Where ShowDialog() ensures the dispatcher does the dispatching and the InvokeShutdown() ensures that the cleanup occurs. Tested by using a 10 msec DispatcherTimer instead of buttons so this happened at a very high rate. I could remove the GC.Collect() calls and memory usage was stable.
At the moment I've no comment about the ActiveX part (will double check and let you know), but I can suggest something related to the WPF code.
This should make the combo items disposable
public class DispCombo : ComboBox, IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
public class DispGrid : Grid, IDisposable
{
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
You will populate disposable controls
public void PopulateControls()
{
var newGrid = new DispGrid();
for (var i = 0; i < 1000; i++)
{
DispCombo newcombo = new DispCombo();
newGrid.Children.Add(newcombo);
}
this.Content = newGrid;
}
So the closing phase would become (disposing instead of setting to null)
private void Window_Closed(object sender, EventArgs e)
{
var grid = Content as DispGrid;
var children = grid.Children;
while (children.Count > 0)
{
var child = children[0] as DispCombo;
grid.Children.Remove(child);
child.Dispose();
}
grid.Dispose();
}
That said, now you can wrap the WPF view in a using clause
public class MainLibrary
{
public bool OpenWindow() //found no ref to bool isRunning
{
using (var mw = new MainWindow())
{
mw.ShowDialog();
mw.Close();
}
return true;
}
public bool CloseWindow()
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
return true;
}
}
with your garbage collection in the close.
These are my memory snapshots after these changes, taken (1) at start, then (2) after the main ShowDialog in the OpenWindow and finally (3) after the CloseWindow
Edit
Finally, if you need to start a Task, calling the Dispatcher, here it is the function
public bool CloseWindow()
{
winClose = () =>
{
mw.Dispatcher.Invoke(() =>
{
mw.Close();
mw.Dispose();
});
};
cleanProc = () =>
{
mw.Dispatcher.Invoke(() =>
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
});
};
Task.Run(() =>
{
winClose.Invoke();
}).ContinueWith(x =>
{
cleanProc.Invoke();
});
return true;
}
with
public bool OpenWindow()
{
mw = new MainWindow();
mw.Show();
return true;
}
My son is writing a simple RPG game that has a number of non-player characters (aka NPC's). Each NPC has an associated "script" that controls its behaviour. We were going to use a mini custom script language to write these behaviours but I'm now wondering if this would be better done in C#5/Async.
Taking a really simple example, suppose one of the NPC's just walks between two points I'm thinking it would be nice to write something like this:
while (true)
{
await WalkTo(100,100);
await WalkTo(200,200);
}
The WalkTo method would be an async method that handles everything to do with walking between the two points and does this over a number of frames from the game loop. It's not a blocking method that can be off-loaded to a background thread.
And this is where I'm stuck... I haven't been able to find any examples using async/await in this manner, but it seems it would be perfect for it.
Ideas?
Here's some very rough pseudo code for what I'd like to do:
class NpcBase
{
// Called from game loop
public void onUpdate(double elapsedTime)
{
// Move the NPC
.
.
.
// Arrived at destination?
if (Arrived)
{
// How do I trigger that the task is finished?
_currentTask.MarkComplete();
}
}
// Async method called by NPC "script"
public async Task WalkTo(int x, int y)
{
// Store new target location
// return a task object that will be "triggered" when the walk is finished
_currentTask = <something??>
return _currentTask;
}
Task _currentTask;
}
Okay, it sounds like one option would be to have a TaskCompletionSource for each frame of the game. You can then await the Task from WalkTo, and set the result in OnUpdate:
private TaskCompletionSource<double> currentFrameSource;
// Called from game loop
public void OnUpdate(double elapsedTime)
{
...
var previousFrameSource = currentFrameSource;
currentFrameSource = new TaskCompletionSource<double>();
// This will trigger all the continuations...
previousFrameSource.SetResult(elapsedTime);
}
// Async method called by NPC "script"
public async Task WalkTo(int x, int y)
{
// Store new target location
while (/* we're not there yet */)
{
double currentTime = await currentFrameSource.Task;
// Move
}
}
I'm not sure how efficient this will be, admittedly... but it should work.
I think I've figured it out in a simple test program
Firstly, I've got a base class for the NPC's like this:
EDIT: Updated NpcBase to use TaskCompletionSource:
public class NpcBase
{
// Derived classes to call this when starting an async operation
public Task BeginTask()
{
// Task already running?
if (_tcs!= null)
{
throw new InvalidOperationException("busy");
}
_tcs = new TaskCompletionSource<int>();
return _tcs.Task;
}
TaskCompletionSource<int> _tcs;
// Derived class calls this when async operation complete
public void EndTask()
{
if (_tcs != null)
{
var temp = _tcs;
_tcs = null;
temp.SetResult(0);
}
}
// Is this NPC currently busy?
public bool IsBusy
{
get
{
return _tcs != null;
}
}
}
For reference, here's the old version of NpcBase with custom IAsyncResult implementation instead of TaskCompletionSource:
// DONT USE THIS, OLD VERSION FOR REFERENCE ONLY
public class NpcBase
{
// Derived classes to call this when starting an async operation
public Task BeginTask()
{
// Task already running?
if (_result != null)
{
throw new InvalidOperationException("busy");
}
// Create the async Task
return Task.Factory.FromAsync(
// begin method
(ac, o) =>
{
return _result = new Result(ac, o);
},
// End method
(r) =>
{
},
// State object
null
);
}
// Derived class calls this when async operation complete
public void EndTask()
{
if (_result != null)
{
var temp = _result;
_result = null;
temp.Finish();
}
}
// Is this NPC currently busy?
public bool IsBusy
{
get
{
return _result != null;
}
}
// Result object for the current task
private Result _result;
// Simple AsyncResult class that stores the callback and the state object
class Result : IAsyncResult
{
public Result(AsyncCallback callback, object AsyncState)
{
_callback = callback;
_state = AsyncState;
}
private AsyncCallback _callback;
private object _state;
public object AsyncState
{
get { return _state; ; }
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get { throw new NotImplementedException(); }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return _finished; }
}
public void Finish()
{
_finished = true;
if (_callback != null)
_callback(this);
}
bool _finished;
}
}
Next, I've got a simple "NPC" that moves in one dimension. When a moveTo operation starts it calls BeginTask in the NpcBase. When arrived at the destination, it calls EndTask().
public class NpcTest : NpcBase
{
public NpcTest()
{
_position = 0;
_target = 0;
}
// Async operation to count
public Task MoveTo(int newPosition)
{
// Store new target
_target = newPosition;
return BeginTask();
}
public int Position
{
get
{
return _position;
}
}
public void onFrame()
{
if (_position == _target)
{
EndTask();
}
else if (_position < _target)
{
_position++;
}
else
{
_position--;
}
}
private int _position;
private int _target;
}
And finally, a simple WinForms app to drive it. It consists of a button and two labels. Clicking the button starts both NPC and their position is displayed on the labels.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void onButtonClick(object sender, EventArgs e)
{
RunNpc1();
RunNpc2();
}
public async void RunNpc1()
{
while (true)
{
await _npc1.MoveTo(20);
await _npc1.MoveTo(10);
}
}
public async void RunNpc2()
{
while (true)
{
await _npc2.MoveTo(80);
await _npc2.MoveTo(70);
}
}
NpcTest _npc1 = new NpcTest();
NpcTest _npc2 = new NpcTest();
private void timer1_Tick(object sender, EventArgs e)
{
_npc1.onFrame();
_npc2.onFrame();
label1.Text = _npc1.Position.ToString();
label2.Text = _npc2.Position.ToString();
}
}
And it works, all seems to be running on the main UI thread... which is what I wanted.
Of course it needs to be fixed to handle cancelling of operations, exceptions etc... but the basic idea is there.
I am building a generic URI retrieval system. Essentially there's a generic class Retriever<T> and it maintains a queue of URIs to be retrieved. It has a separate thread that handles that queue as fast as it can. An example of a type of URI, as indicated in the question title, is HTTP type URIs.
The problem is, when I get down to requesting that the resource be retrieved, via an abstract method T RetrieveResource(Uri location), it slow down due to a lack of asynchrony.
Changing the return type of RetrieveResource to Task<T> was my first thought. However, that seems to make tasks pile up and cause lots of problems when we have thousands of outstanding tasks. It appears to create many actual threads instead of utilizing the thread pool. I imagine this just slows everything down because there are too many things going on at once, so nothing individually is making significant progress.
It's expected that we will have a large number of queued items to retrieve and that they cannot be handled as fast as they are enqueued. There is an opportunity for the system to catch up, over time; but it's definitely not quick.
I've also thought about instead of maintaining a queue and a thread to handle it... to just queue a work item on the ThreadPool. However, I'm not sure that this is ideal if say I need to shut the system down before all work items are handled or later want to allow for prioritization or something.
We also know that retrieving a resource is a time consuming process (0.250 - 5 seconds), but not necessarily a resource intense process. We are fine parallelizing this out to hundreds of requests.
Our requirements are:
URIs can be enqueued from any thread, even when the system is working on the queue
Retrieval may need to later be capable of being prioritized
Retrieval should be able to be paused
Minimal spinning should occur when nothing is being retrieved (BlockingCollection is useful here).
Is there a good way to parallelize this without introducing unnecessary complexity?
Below is some existing code we have, as an example.
public abstract class Retriever<T> : IRetriever<T>, IDisposable
{
private readonly Thread worker;
private readonly BlockingCollection<Uri> pending;
private volatile int isStarted;
private volatile int isDisposing;
public event EventHandler<RetrievalEventArgs<T>> Retrieved;
protected Retriever()
{
this.worker = new Thread(this.RetrieveResources);
this.pending = new BlockingCollection<Uri>(new ConcurrentQueue<Uri>());
this.isStarted = 0;
this.isDisposing = 0;
}
~Retriever()
{
this.Dispose(false);
}
private void RetrieveResources()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.pending);
}
Uri location = this.pending.Take();
// This is what needs to be concurrently done.
// In this example, it's synchronous, but just on a separate thread.
T result = this.RetrieveResource(location);
// At this point, we would fire our event with the retrieved data
}
}
protected abstract T RetrieveResource(Uri location);
protected void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this.isDisposing, 1, 0) == 1)
{
return;
}
if (disposing)
{
this.pending.CompleteAdding();
this.worker.Join();
}
}
public void Add(Uri uri)
{
try
{
this.pending.Add(uri);
}
catch (InvalidOperationException)
{
return;
}
}
public void AddRange(IEnumerable<Uri> uris)
{
foreach (Uri uri in uris)
{
try
{
this.pending.Add(uri);
}
catch (InvalidOperationException)
{
return;
}
}
}
public void Start()
{
if (Interlocked.CompareExchange(ref this.isStarted, 1, 0) == 1)
{
throw new InvalidOperationException("The retriever is already started.");
}
if (this.worker.ThreadState == ThreadState.Unstarted)
{
this.worker.Start();
}
Monitor.Pulse(this.pending);
}
public void Stop()
{
if (Interlocked.CompareExchange(ref this.isStarted, 0, 1) == 0)
{
throw new InvalidOperationException("The retriever is already stopped.");
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}
To build on the example above... a solution to this that I think adds too much complexity or rather, weird code... would be this.
private void RetrieveResources()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.pending);
}
Uri location = this.pending.Take();
Task<T> task = new Task<T>((state) =>
{
return this.RetrieveResource(state as Uri);
}, location);
task.ContinueWith((t) =>
{
T result = t.Result;
RetrievalEventArgs<T> args = new RetrievalEventArgs<T>(location, result);
EventHandler<RetrievalEventArgs<T>> callback = this.Retrieved;
if (!Object.ReferenceEquals(callback, null))
{
callback(this, args);
}
});
task.Start();
}
}
I've come up with a pretty good solution I think. I abstracted both the method a resource is retrieved and the result's representation. This allows support for retrieval of arbitrary URIs with arbitrary results; kind of like some URI driven "ORM".
It supports variable concurrency levels. The other day when I posted the question, I was forgetting that asynchrony and concurrency are quite different and that all I was achieving with tasks was asynchrony and jamming up the task scheduler because what I really wanted was concurrency.
I added in cancellation because it seemed like a good idea to have start/stop capabilities.
public abstract class Retriever<T> : IRetriever<T>
{
private readonly object locker;
private readonly BlockingCollection<Uri> pending;
private readonly Thread[] threads;
private CancellationTokenSource cancellation;
private volatile int isStarted;
private volatile int isDisposing;
public event EventHandler<RetrieverEventArgs<T>> Retrieved;
protected Retriever(int concurrency)
{
if (concurrency <= 0)
{
throw new ArgumentOutOfRangeException("concurrency", "The specified concurrency level must be greater than zero.");
}
this.locker = new object();
this.pending = new BlockingCollection<Uri>(new ConcurrentQueue<Uri>());
this.threads = new Thread[concurrency];
this.cancellation = new CancellationTokenSource();
this.isStarted = 0;
this.isDisposing = 0;
this.InitializeThreads();
}
~Retriever()
{
this.Dispose(false);
}
private void InitializeThreads()
{
for (int i = 0; i < this.threads.Length; i++)
{
Thread thread = new Thread(this.ProcessQueue)
{
IsBackground = true
};
this.threads[i] = thread;
}
}
private void StartThreads()
{
foreach (Thread thread in this.threads)
{
if (thread.ThreadState == ThreadState.Unstarted)
{
thread.Start();
}
}
}
private void CancelOperations(bool reset)
{
this.cancellation.Cancel();
this.cancellation.Dispose();
if (reset)
{
this.cancellation = new CancellationTokenSource();
}
}
private void WaitForThreadsToExit()
{
foreach (Thread thread in this.threads)
{
thread.Join();
}
}
private void ProcessQueue()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.locker);
}
Uri location;
try
{
location = this.pending.Take(this.cancellation.Token);
}
catch (OperationCanceledException)
{
continue;
}
T data;
try
{
data = this.Retrieve(location, this.cancellation.Token);
}
catch (OperationCanceledException)
{
continue;
}
RetrieverEventArgs<T> args = new RetrieverEventArgs<T>(location, data);
EventHandler<RetrieverEventArgs<T>> callback = this.Retrieved;
if (!Object.ReferenceEquals(callback, null))
{
callback(this, args);
}
}
}
private void ThowIfDisposed()
{
if (this.isDisposing == 1)
{
throw new ObjectDisposedException("Retriever");
}
}
protected abstract T Retrieve(Uri location, CancellationToken token);
protected virtual void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this.isDisposing, 1, 0) == 1)
{
return;
}
if (disposing)
{
this.CancelOperations(false);
this.WaitForThreadsToExit();
this.pending.Dispose();
}
}
public void Start()
{
this.ThowIfDisposed();
if (Interlocked.CompareExchange(ref this.isStarted, 1, 0) == 1)
{
throw new InvalidOperationException("The retriever is already started.");
}
Monitor.PulseAll(this.locker);
this.StartThreads();
}
public void Add(Uri location)
{
this.pending.Add(location);
}
public void Stop()
{
this.ThowIfDisposed();
if (Interlocked.CompareExchange(ref this.isStarted, 0, 1) == 0)
{
throw new InvalidOperationException("The retriever is already stopped.");
}
this.CancelOperations(true);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}
I have a BindingList databound to a datgridview. I'm using it to keep track of some real-time prices. The method 'update(Quote quote)' is called multiple times a second by various threads. If the datagridview doesn't contain the Quote, it is added. If it does, the values of the quote are updated. I don't want the same quote to appear in the BindingList (or on the GUI) twice, so I tried to put a lock around the operation that checks whether the value is in the list or not. It doesn't work! What am I doing wrong? I've tried two different ways of locking, and am locking on a String object rather than just an object. The problem is definitely in the BeginInvoke(new MethodInvoker(delegate() { activeQuotes.Insert(0, quote); })); call (which is probably taking some time), but if I make that synchronous, the 'add' method throws a 'cross-threading' error. . . What can I do to avoid the cross-threading error, but ensure that the lock works also??
public BindingList<Quote> activeQuotes = new BindingList<Quote>();
object lockObject = "lockObject";
dataGridViewActive.DataSource = activeQuotes;
public void update(Quote quote)
{
//lock (lockObject)
if(Monitor.TryEnter(lockObject))
{
try
{
if (!activeQuotes.Contains(quote))
{
try
{
activeQuotes.Add(quote);
AddQuote(quote);
}
catch (Exception ex)
{
Console.WriteLine("Datagridview!!!!!!");
}
}
else
{
int index = activeQuotes.IndexOf(quote);
activeQuotes[index].Bid = quote.Bid;
activeQuotes[index].Ask = quote.Ask;
activeQuotes[index].Mid = quote.Mid;
activeQuotes[index].Spread = quote.Spread;
activeQuotes[index].Timestamp = quote.Timestamp;
}
finally
{
Monitor.Exit(lockObject);
}
}
private void AddQuote(Quote quote)
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate() { activeQuotes.Insert(0, quote); }));
BeginInvoke(new MethodInvoker(delegate() { dataGridViewActive.Refresh(); }));
BeginInvoke(new MethodInvoker(delegate() { dataGridViewActive.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); }));
}
else
{
activeQuotes.Add(quote);
dataGridViewActive.Refresh();
dataGridViewActive.AutoResizeColumns (DataGridViewAutoSizeColumnsMode.AllCells);
}
}
I'd appreciate any help at all on this.
Thanks.
this code I wrote before will do
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BindingListInvoked<Name> names;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
names = new BindingListInvoked<Name>(dataGridView1);
dataGridView1.DataSource = names;
new Thread(() => names.Add(new Name() { FirstName = "Larry", LastName = "Lan" })).Start();
new Thread(() => names.Add(new Name() { FirstName = "Jessie", LastName = "Feng" })).Start();
}
}
public class BindingListInvoked<T> : BindingList<T>
{
public BindingListInvoked() { }
private ISynchronizeInvoke _invoke;
public BindingListInvoked(ISynchronizeInvoke invoke) { _invoke = invoke; }
public BindingListInvoked(IList<T> items) { this.DataSource = items; }
delegate void ListChangedDelegate(ListChangedEventArgs e);
protected override void OnListChanged(ListChangedEventArgs e)
{
if ((_invoke != null) && (_invoke.InvokeRequired))
{
IAsyncResult ar = _invoke.BeginInvoke(new ListChangedDelegate(base.OnListChanged), new object[] { e });
}
else
{
base.OnListChanged(e);
}
}
public IList<T> DataSource
{
get
{
return this;
}
set
{
if (value != null)
{
this.ClearItems();
RaiseListChangedEvents = false;
foreach (T item in value)
{
this.Add(item);
}
RaiseListChangedEvents = true;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
}
}
public class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
I think you should change your BeginInvoke to just Invoke. You need to get it on the UI thread, not begin an async operation. Otherwise your lock could get released before the BeginInvoke target gets invoked because control is returned immediately upon calling BeginInvoke. Calling Invoke will block that thread on that call until the Invoke target completes then return control back to your thread, which will ensure the lock is kept.
Also, have you considered using a lock block instead of Monitor method calls? It's basically the same thing but prevents you from needing the try/finally. I don't see that you're using any retry or benefit from the TryEnter, but perhaps the code sample doesn't demonstrate that.
All the examples I have seen using SynchronisationContext.Post have been used in the same class. What I have is the UI thread passing some by-ref arguments to a threadwrapper class, updating the arguments and then I want it to update some labels etc on the UIThread.
internal class ConnThreadWrapper
{
....
public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus =
delegate { };
public void updateUIThread(string conn, bool connected)
{
uiContext.Post(new SendOrPostCallback((o) =>
{
updateConnStatus(this,
new MyEventArgs<String, Boolean>(conn,
connected));
}),
null);
}
}
//on ui thread
public void updateConnStatus(object sender, MyEventArgs<String, Boolean> e)
{
switch (e.val1)
{
case "CADS" :
if (e.val2 == true)
{
}
The Event seems to fire without any errors but nothing is ever received on the uiThread - i'm not sure if my signature for the sub updateConnStatus is correct or if it works like this. I obviously want the event to handled on the uithread and update the labels from that sub.
In a previous vb.net project I used to reference the form directly on the thread and used a delegate to invoke a callback but apparently this was a bad design as I was mixing application layers. I wanted to use the sync context as it was meant to be thread safe but most of the examples i've seen have used invoke.
Any ideas what I'm missing? Thanks
I wrote this helper class which works for me. Prior to using this class call InitializeUiContext() on UI thread somewhere on application start.
public static class UiScheduler
{
private static TaskScheduler _scheduler;
private static readonly ConcurrentQueue<Action> OldActions =
new ConcurrentQueue<Action>();
public static void InitializeUiContext()
{
_scheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private static void ExecuteOld()
{
if(_scheduler != null)
{
while(OldActions.Count > 0)
{
Action a;
if(OldActions.TryDequeue(out a))
{
UiExecute(_scheduler, a);
}
}
}
}
private static void UiExecute(TaskScheduler scheduler,
Action a,
bool wait = false)
{
//1 is usually UI thread, dunno how to check this better:
if (Thread.CurrentThread.ManagedThreadId == 1)
{
a();
}
else
{
Task t = Task.Factory.StartNew(a,
CancellationToken.None,
TaskCreationOptions.LongRunning,
scheduler);
if (wait) t.Wait();
}
}
public static void UiExecute(Action a, bool wait = false)
{
if (a != null)
{
if (_scheduler != null)
{
ExecuteOld();
UiExecute(_scheduler, a, wait);
}
else
{
OldActions.Enqueue(a);
}
}
}
}
In the end I ditched the ThreadWrapper and trying to marshal the event to the UI Thread and used a Task instead, in fact I think I can use task to do most of the stuff in this project so happy days.
Task<bool> t1 = new Task<bool>(() => testBB(ref _bbws_wrapper));
t1.Start();
Task cwt1 = t1.ContinueWith(task => { if (t1.Result == true) { this.ssi_bb_conn.BackColor = Color.Green;} else { this.ssi_bb_conn.BackColor = Color.Red; } }, TaskScheduler.FromCurrentSynchronizationContext());
.....
private static bool testBB(ref BBWebserviceWrapper _bbwsw)
{
try
{
//test the connections
if (_bbwsw.initialize_v1() == true)
{
if (_bbwsw.loginUser("XXXXXXXX", "XXXXXXXXX") == true)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
catch
{
return false;
}
}