I have a problem with increasing memory. I have an image, that comes from a camera. The image is processed by a function with unmanaged code. If the expected pattern could not be found, this function takes a long time (some seconds). If the pattern can be found it returns a result very fast (some ms).
I tried to start the postprocessing in a new Thread and Abort it after 200ms. So far this works. Now I have the problem, that my memory grows. Maybe the using clause doesn't work as expected and the image is kept in memory...
private void ImageWorker()
{
while (_imageWorkerRunning)
{
try
{
using (var img = CameraHelper.GetImage())
{
var waiter = new ManualResetEvent(false);
ProcessResult result = null;
var thd = new Thread(() => {
result = UnManagedImageProcessor.Process(img);
waiter.Set();
});
thd.Start();
waiter.WaitOne(200);
if (thd.ThreadState == ThreadState.Running || result == null)
{
thd.Abort();
while (thd.ThreadState != ThreadState.Aborted) new ManualResetEvent(false).WaitOne(10);
}
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
Does the GC work fine on aborted Threads? I think maybe this is my problem...
Solutiuon:
I changed my code to the following. Now I have two parallel tasks. The first is getting images and check, if processing is available.
If it is, the image is provided to this ImageProcessing task. That displays image only on Success (then processing is fast and each picture can be processed).
If processing is not successfull it takes some time and the image is displayed only as live image (by ImageWorker).
private readonly object _imageLock = new object();
private ExtendedImage _sharedProcessingImage;
private readonly ManualResetEvent _processingWaiter = new ManualResetEvent(false);
private bool _processingWaits = false;
private void ImageWorker()
{
while (_imageWorkerRunning) {
try {
var img = CameraHelper.GetImage();
if (_processingWaits) {
//processing available --> process image
lock (_imageLock) {
_sharedProcessingImage = img;
}
_processingWaits = false;
_processingWaiter.Set();
}
else {
//Processing in progress --> Only display image
Application.Current.Dispatcher.Invoke(() => DisplayImage = img);
}
new ManualResetEvent(false).WaitOne(50);
}
catch (Exception e) {
_log.Error(e);
}
}
}
private void ImageProcessing()
{
while (_imageWorkerRunning) {
_processingWaits = true;
_processingWaiter.WaitOne();
_processingWaiter.Reset();
lock (_imageLock) {
try {
result = UnManagedImageProcessor.Process(_sharedProcessingImage);
// ... handle result
if(result.Succeeded) Application.Current.Dispatcher.Invoke(() => DisplayImage = _sharedProcessingImage);
}
catch (Exception e) {
_log.Error(e);
}
}
}
}
Thanks for your help.
What I propose to you is to use BlockingCollection.
To display the images you can use a locker, every time the UI is idle you lock the object, get the last image and dispose the previus one. Also, everytime a image is processed you lock the object and set the var to the last one.
Display logic:
readonly object lastProcessdImageLocker = new object();
Bitmap lastProcessdImage;
//Every time a image process is done:
lock(lastProcessdImageLocker)
lastProcessdImage = imageJustProcessed;
//Every time the UI thread is idle
lock(lastProcessdImageLocker)
myPictureboxImage = lastProcessdImage;
//Here you should also dispose the previus myPictureboxImage so you prevent your memory usage to grow fast!
See this post for more info about WPF and also WinForm render loop
Sample code of the use of BlockingCollection to consume (process) camera images:
BlockingCollection<Bitmap> cameraImages = new BlockingCollection<Bitmap>();
//use another theard to fill up the cameraImages, like that:
//cameraImages.Add(CameraHelper.GetImage());
void StartProcess()
{
if (processImageThread== null || !processImageThread.IsAlive)
{
processImageThread= new Thread(ProcessLoop);
processImageThread.Name = "ProcessLoop";
processImageThread.IsBackground = true;
processImageThread.Start();
Console.TraceInformation("ProcessLoop started");
}
}
private void ProcessLoop()
{
try
{
foreach (img in cameraImages.GetConsumingEnumerable(CancelProcessing.Token))
{
// Do your stuff
}
}
catch (OperationCanceledException)
{
Console.WriteLine("ProcessLoop OperationCanceledException.");
}
finally
{
}
}
If your cameraImages count grows too fast (getting out of memory), you need to reduce the process time or stop the camera for some time.
Related
I have code
private void AbrirConexao(string strConexao)
{
try
{
conexao = new NpgsqlConnection(strConexao);
conexao.Open();
}
catch (Exception)
{
ReconectarDB(null, strConexao);
}
}
public bool ReconectarDB(string strConexao)
{
bool erroConexao = false;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (obj, ea) =>
{
int erro = 0;
while (erro <= 4)
{
Thread.Sleep(1000);
try
{
conexao = new NpgsqlConnection(strConexao);
conexao.Open();
erroConexao = false;
break;
}
catch
{
erro++;
erroConexao = true;
}
}
};
bw.RunWorkerCompleted += (obj, ea) =>
{
if (erroConexao)
DialogReconectando.AlterarTela(ErroConexao.SemConexao);
else
DialogReconectando.Close();
};
bw.RunWorkerAsync();
Application.Current.Dispatcher.Invoke(new Action(() =>
{
if (DialogReconectando == null || Conexao.DialogReconectando.IsLoaded == false)
DialogReconectando = new DialogErroConexao(ErroConexao.Reconectando);
if(DialogReconectando.ShowActivated)
{
DialogReconectando.ShowActivated = true;
DialogReconectando.ShowDialog();
}
}));
return erroConexao;
}
I am using the Open Connection method to connect to the database. and when the connection fails, ReconnectDB is trying to reconnect with the database. If it fails, a Window is opened that there are two buttons, Retry and Abort the System.
The problem is that there are situations that I use other concurrent threads that makes requests with the database. In those cases, I would not want it to display a new Window. So if there is a Window open, I would like the Thread to lock until the Window is closed. I tried to solve the problem using EventWaitHandle. However, Window is also caught in this situation. Would you have any idea how you could solve this problem?
It depends on what you want the second thread to do. If you want the second thread to simply skip over showing the window, you can use a semaphore to ensure that only a single thread shows the window, like this:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
private void ShowWindowNonBlocking()
{
bool acquiredLock = false;
try
{
acquiredLock = semaphore.Wait(0);
if (acquiredLock)
{
// This thread now has exclusive access to the isWindowShown variable
var result = MessageBox.Show(
"Retry the connection?",
"Connection Failed",
MessageBoxButtons.RetryCancel);
if (result == DialogResult.Retry)
{
// Retry the connection
}
}
else
{
// Another thread is showing the window
}
}
finally
{
if (acquiredLock)
{
semaphore.Release();
}
}
}
Here is a good site that I refer back to from time to time on locking mechanisms: http://www.albahari.com/threading/part2.aspx#_Semaphore
If however, you want the second thread to block until the first window is finished (for example, if you want to know what the result of the window was in order to know whether to retry on the second thread), you can use a lock, like this:
private object windowLock = new object();
private void ShowWindowBlocking()
{
lock (windowLock)
{
var result = MessageBox.Show(
"Retry the connection?",
"Connection Failed",
MessageBoxButtons.RetryCancel);
if (result == DialogResult.Retry)
{
// Retry the connection
}
}
}
If you need further clarification, let me know and I will try to expand the answer.
There are many questions and articles on the subject of using a .NET Queue properly within a multi threaded application, however I can't find subject on our specific problem.
We have a Windows Service that receives messages onto a queue via one thread and is then dequeued and processed within another.
We're using lock when queuing and dequeuing, and the service had run fine for around 2 years without any problems. One day we noticed that thousands of messages had been logged (and so had been queued) but were never dequeued/processed, they seem to have been skipped somehow, which shouldn't be possible for a queue.
We can't replicate the circumstances that caused it as we have no real idea what caused it considering that day was no different from any of the others as far as we're aware.
The only idea we have is to do with the concurrency of the queue. We're not using the ConcurrentQueue data-type, which we plan on using in the hope it is a remedy.
One idea, looking at the source of the Queue type, is that it uses arrays internally, which have to be resized once these buffers have reached a certain length. We hypothesised that when this is being done some of the messages were lost.
Another idea from our development manager is that using multiple threads on a multicore processor setup means that even though locks are used, the individual cores are working on the data in their local registers, which can cause them to be working on different data. He said they don't work on the same memory and seems to think lock only works as expected one a single core processor using multiple threads.
Reading more about ConcurrentQueue's use of volatile I'm not sure that this would help, as I've read that using lock provides a stronger guarantee of threads using the most up-to-date state of memory.
I don't have much knowledge on this specific subject, so my question is whether the manager's idea sounds plausible, and whether we might have missed something that's required for the queue to be used properly.
Code snippet for reference (forgive the messy code, it does need refactoring):
public sealed class Message
{
public void QueueMessage(long messageId, Message msg)
{
lock (_queueLock)
{
_queue.Enqueue(new QueuedMessage() { Id = messageId, Message = msg });
}
}
public static void QueueMessage(string queueProcessorName, long messageId, Message msg)
{
lock (_messageProcessors[queueProcessorName]._queueLock)
{
_messageProcessors[queueProcessorName].QueueMessage(messageId, msg);
_messageProcessors[queueProcessorName].WakeUp(); // Ensure the thread is awake
}
}
public void WakeUp()
{
lock(_monitor)
{
Monitor.Pulse(_monitor);
}
}
public void Process()
{
while (!_stop)
{
QueuedMessage currentMessage = null;
try
{
lock (_queueLock)
{
currentMessage = _queue.Dequeue();
}
}
catch(InvalidOperationException i)
{
// Nothing in the queue
}
while(currentMessage != null)
{
IContext context = new Context();
DAL.Message msg = null;
try
{
msg = context.Messages.SingleOrDefault(x => x.Id == currentMessage.Id);
}
catch (Exception e)
{
// TODO: Handle these exceptions better. Possible infinite loop.
continue; // Keep retrying until it works
}
if (msg == null) {
// TODO: Log missing message
continue;
}
try
{
msg.Status = DAL.Message.ProcessingState.Processing;
context.Commit();
}
catch (Exception e)
{
// TODO: Handle these exceptions better. Possible infinite loop.
continue; // Keep retrying until it works
}
bool result = false;
try {
Transformation.TransformManager mgr = Transformation.TransformManager.Instance();
Transformation.ITransform transform = mgr.GetTransform(currentMessage.Message.Type.Name, currentMessage.Message.Get("EVN:EventReasonCode"));
if (transform != null){
msg.BeginProcessing = DateTime.Now;
result = transform.Transform(currentMessage.Message);
msg.EndProcessing = DateTime.Now;
msg.Status = DAL.Message.ProcessingState.Complete;
}
else {
msg.Status = DAL.Message.ProcessingState.Failed;
}
context.Commit();
}
catch (Exception e)
{
try
{
context = new Context();
// TODO: Handle these exceptions better
Error err = context.Errors.Add(context.Errors.Create());
err.MessageId = currentMessage.Id;
if (currentMessage.Message != null)
{
err.EventReasonCode = currentMessage.Message.Get("EVN:EventReasonCode");
err.MessageType = currentMessage.Message.Type.Name;
}
else {
err.EventReasonCode = "Unknown";
err.MessageType = "Unknown";
}
StringBuilder sb = new StringBuilder("Exception occured\n");
int level = 0;
while (e != null && level < 10)
{
sb.Append("Message: ");
sb.Append(e.Message);
sb.Append("\nStack Trace: ");
sb.Append(e.StackTrace);
sb.Append("\n");
e = e.InnerException;
level++;
}
err.Text = sb.ToString();
}
catch (Exception ne) {
StringBuilder sb = new StringBuilder("Exception occured\n");
int level = 0;
while (ne != null && level < 10)
{
sb.Append("Message: ");
sb.Append(ne.Message);
sb.Append("\nStack Trace: ");
sb.Append(ne.StackTrace);
sb.Append("\n");
ne = ne.InnerException;
level++;
}
EventLog.WriteEntry("Service", sb.ToString(), EventLogEntryType.Error);
}
}
try
{
context.Commit();
lock (_queueLock)
{
currentMessage = _queue.Dequeue();
}
}
catch (InvalidOperationException e)
{
currentMessage = null; // No more messages in the queue
}
catch (Exception ne)
{
StringBuilder sb = new StringBuilder("Exception occured\n");
int level = 0;
while (ne != null && level < 10)
{
sb.Append("Message: ");
sb.Append(ne.Message);
sb.Append("\nStack Trace: ");
sb.Append(ne.StackTrace);
sb.Append("\n");
ne = ne.InnerException;
level++;
}
EventLog.WriteEntry("Service", sb.ToString(), EventLogEntryType.Error);
}
}
lock (_monitor)
{
if (_stop) break;
Monitor.Wait(_monitor, TimeSpan.FromMinutes(_pollingInterval));
if (_stop) break;
}
}
}
private object _monitor = new object();
private int _pollingInterval = 10;
private volatile bool _stop = false;
private object _queueLock = new object();
private Queue<QueuedMessage> _queue = new Queue<QueuedMessage>();
private static IDictionary<string, Message> _messageProcessors = new Dictionary<string, Message>();
}
so my question is whether the manager's idea sounds plausible
Uhm. No. If all those synchronization measures would only work on single core machines, the world would have ended in complete Chaos decades ago.
and whether we might have missed something that's required for the queue to be used properly.
As far as your description goes, you should be fine. I would look at how you found out that you have that problem. logs coming in but then vanishing without being properly dequeued, wouldn't that be the default case if I simply turned off the service or rebooted the machine? Are you sure you lost them while your application was actually running?
You declare the object to be used for the lock as private object.
If you try this:
class Program
{
static void Main(string[] args)
{
Test test1 = new Test();
Task Scan1 = Task.Run(() => test1.Run("1"));
Test test2 = new Test();
Task Scan2 = Task.Run(() => test2.Run("2"));
while(!Scan1.IsCompleted || !Scan2.IsCompleted)
{
Thread.Sleep(1000);
}
}
}
public class Test
{
private object _queueLock = new object();
public async Task Run(string val)
{
lock (_queueLock)
{
Console.WriteLine($"{val} locked");
Thread.Sleep(10000);
Console.WriteLine($"{val} unlocked");
}
}
}
You will notice that the code that lies under the lock is executed even if another thread is running inside.
But if you change
private object _queueLock = new object();
To
private static object _queueLock = new object();
It changes how your lock works.
Now, this being your issue depends on if you have multiple instances that class or everything is running withing that same class.
I'm trying to get my head around threads, in my current application threads would be the best way to deal with it, what i have:
public void threadsTest() {
Invoke(new MethodInvoker(() => {
// loop over the listview getting the first value
foreach (ListViewItem item in listViewBacklinks.Items)
{
// try...
try
{
var mainURL = item.Text;
using (WebClient wc = new WebClient())
{
try
{
var pageHtml = wc.DownloadString(mainURL);
if (pageHtml.Contains(Text))
{
var subitems = item.SubItems.Add("anchor text");
item.BackColor = Color.Green;
}
else
{
item.BackColor = Color.Red;
}
} catch (Exception)
{
item.BackColor = Color.Red;
}
//Helpers.returnMessage("Work done!");
}
} catch (Exception ex) {
Helpers.returnMessage(ex.ToString());
}
}}));
}
private void btnAnalyzeAnchorText_Click(object sender, EventArgs e)
{
// attempting threads
var t = new Thread(threadsTest);
t.Start();
}
I thought like the backgroundWorker it would not freeze up the GUI but it did so i put in the invoke to access GUI elements, i don't think it looks right, the way it is now the GUI is still unresponsive until the work is done, i have viewed some tutorials but it's not totally sinking in, any help/tips on cracking threads would be great.
This is what you need to do:
public void threadsTest(string[] urls)
{
var results = new Dictionary<string, string>();
foreach (string mainURL in urls)
{
using (WebClient wc = new WebClient())
{
var pageHtml = wc.DownloadString(mainURL);
results[mainUrl] = pageHtml;
}
}
Invoke(new MethodInvoker(() => ProcessResults(results)));
}
There are no UI elements in this code, just the heavy lifting of the WebClient.
Then in the new ProcessResults you're back on the UI thread so then you can set your results.
The call to the thread needs to pass through an array of urls (strings) but you get that before creating the thread so you're still in the UI thread and thus it is safe to do.
I wrote the simplified version of my program below. Process A launches a child process (Process B). I use an anonymous pipe to write information about the progress of a method running on process B. Meanwhile I have a function in process A that continually reads from a stream to see if there is a new update coming in from the pipe. If there is, the form on process A is updated to reflect the progress. This works as expected, however I am wondering if there is a better way to accomplish this without having to continually check the stream to see if there are any new updates to the progress.
/////////////////
///Process A ////
/////////////////
public void LaunchProcessB()
{
using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In,
HandleInheritability.Inheritable))
{
var _Process = new Process();
_Process.StartInfo.FileName = exeString;
_Process.StartInfo.Arguments = pipeServer.GetClientHandleAsString()
_Process.StartInfo.RedirectStandardOutput = true;
_Process.StartInfo.RedirectStandardInput = true;
_Process.StartInfo.CreateNoWindow = true;
_Process.StartInfo.UseShellExecute = false;
_Process.Start(); //launches process B
pipeServer.DisposeLocalCopyOfClientHandle();
using (StreamReader sr = new StreamReader(pipeServer))
{
try
{
while (true)
{
string temp = sr.ReadLine();
if (temp == null) break;
int result;
if (Int32.TryParse(temp, out result))
ShowDocumentProgress(result);
else ShowProgress(temp);
}
}
catch (Exception)
{
//error occured when reading from stream.
}
}
if (!_Process.Responding && !_Process.HasExited)
{
_Process.Kill();
return;
}
_Process.WaitForExit(10000);
}
}
private void ShowProgressPercent(int percentage)
{
if (percentage > currentPercentage)
{
progressBar.Value = percentage;
}
}
private void ShowProgress(string progressString)
{
labelMessage.Text = progressString;
}
/////////////////
///Process B ////
/////////////////
private StreamWriter _progressWriter;
private PipeStream _progressPipe;
static int Main(string[] args)
{
using (progressPipe = new AnonymousPipeClientStream(PipeDirection.Out, args[0]))
using (_progressWriter = new StreamWriter(_progressPipe))
{
RunLongProcess()
}
}
private void RunLongProcess()
{
//attaches events to PercentProgress and StageProgress methods.
}
private void PercentProgress(int percentage)
{
_progressWriter.WriteLine(percentage.ToString());
_progressPipe.WaitForPipeDrain();
}
private void StageProgress(string stage)
{
_progressWriter.WriteLine(stage);
_progressPipe.WaitForPipeDrain();
}
The while condition is not necessary. Simply read until temp is null. That's the end signal of the stream.
Make this a while(true) loop.
I think you also need to add exception handling to catch the process terminating and severing the pipe. !_Process.HasExited && pipeServer.IsConnected is not enough because it might be true but immediately switch to false after the test.
I also would add a WaitForExit at the end to make sure the system is quiesced before you continue.
I am struggling with threading.
The problem is when I am iterating trough foreach loop.
When setting this.Document, the application performs login, that is triggered with an event and takes few seconds to complete. In the worker_RunWorkerCompleted method I need to perform some actions that depend on current login information.
The problem is that before I can perform this action for the first file, the this.Document already changes making the application perform another login. This way I can never actually perform my actions.
My question is: How can I pause the next thread until previous thread has completed.
Is there any other solution to my problem?
I tried with AutoResetEvent but I got no luck. I set waitOne() just after the RunWorkerAsync call and .Set() in the RunWorkerCompleted. The code never gets to RunWorkerCompleted...
Here is the code:
public void Start(object obj)
{
try
{
foreach (KeyValuePair<string, Stream> pair in this.CollectionOfFiles)
{
Worker = new BackgroundWorker();
Worker.DoWork += new DoWorkEventHandler(worker_DoWork);
Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
using (Stream stream = pair.Value)
{
primaryDocument = new Document(stream);
DataHolderClass dataHolder = new DataHolderClass();
dataHolder.FileName = pair.Key;
dataHolder.Doc = secondaryDocument;
//background thread call
Worker.RunWorkerAsync(dataHolder);
}
}
}
catch (Exception ex)
{
// exception logic
}
finally
{
// complete logic
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
DataHolderClass dataHolder = ((DataHolderClass)e.Argument);
// setting this attribute triggers execution of login event
this.Document = dataHolder.Doc;
e.Result = (dataHolder);
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// here I need to perform some actions that are depending on the current login
DataHolderClass dataHolder = ((DataHolderClass)e.Result);
this.eventAggregator.GetEvent<ActionEvent>().Publish(new Message(EMessageType.Info) { Title = dataHolder.FileName });
}
no9,
Try the following:
System.Threading.ManualResetEvent _busy = new System.Threading.ManualResetEvent(false);
void ResumeWorker()
{
// Start the worker if it isn't running
if (!backgroundWorker1.IsBusy) backgroundWorker1.RunWorkerAsync(dataHolder);
// Unblock the worker
_busy.Set();
}
void PauseWorker()
{
// Block the worker
_busy.Reset();
}
void CancelWorker()
{
if (backgroundWorker1.IsBusy) {
// Set CancellationPending property to true
backgroundWorker1.CancelAsync();
// Unblock worker so it can see that
_busy.Set();
}
}
then in your code run the method.
Let me know if it works :)
class SimpleWaitPulse
{
static readonly object _locker = new object();
static bool _go;
static void Main()
{ // The new thread will block
new Thread (Work).Start(); // because _go==false.
Console.ReadLine(); // Wait for user to hit Enter
lock (_locker) // Let's now wake up the thread by
{ // setting _go=true and pulsing.
_go = true;
Monitor.Pulse (_locker);
}
}
static void Work()
{
lock (_locker)
while (!_go)
Monitor.Wait (_locker); // Lock is released while we’re waiting
Console.WriteLine ("Woken!!!");
}
}
Can you use pulse ?
Taken from : Threading in C# from albahari.com
Well, the design is terrible... but if you need to stick to it, you can set wait handles in a previous worker and wait for it in next. This is the minimal fix, still quite an abomination:
public void Start(object obj)
{
try
{
BackgroundWorker previousWorker = null;
DataHolderClass previousWorkerParams = null;
foreach (KeyValuePair<string, Stream> pair in this.CollectionOfFiles)
{
// signal event on previous worker RunWorkerCompleted event
AutoResetEvent waitUntilCompleted = null;
if (previousWorker != null)
{
waitUntilCompleted = new AutoResetEvent(false);
previousWorker.RunWorkerCompleted += (o, e) => waitUntilCompleted.Set();
// start the previous worker
previousWorker.RunWorkerAsync(previousWorkerParams);
}
Worker = new BackgroundWorker();
Worker.DoWork += (o, e) =>
{
// wait for the handle, if there is anything to wait for
if (waitUntilCompleted != null)
{
waitUntilCompleted.WaitOne();
waitUntilCompleted.Dispose();
}
worker_DoWork(o, e);
};
using (Stream stream = pair.Value)
{
primaryDocument = new Document(stream);
DataHolderClass dataHolder = new DataHolderClass();
dataHolder.FileName = pair.Key;
dataHolder.Doc = secondaryDocument;
// defer running this worker; we don't want it to finish
// before adding additional completed handler
previousWorkerParams = dataHolder;
}
previousWorker = Worker;
}
if (previousWorker != null)
{
previousWorker.RunWorkerAsync(previousWorkerParams);
}
}
catch (Exception ex)
{
// exception logic
}
finally
{
// complete logic
}
}