In my program there is a BackgroundWorker class that preloads the images to BitmapImage object. I need to pass that preloaded image to the main application(WPF), where it will be copied to another BitmapImage object. This seems to be working, however, when i try
imgViewer.Source = imgNext; //imgNext is a main app copy of the preloaded image
an error occurs meaning that that object(imgNext) is owned by another thread and it cannot be used.
Any ideas how to get rid of it and get the code working?
Thanks everybody for answering!
In fact, I managed to solve this problem by creating a static BitmapImage inside App class.
Before using it, I do
App.iNext = null;
Then I load the actual image and freeze it, so this static property can be accessed from everywhere. When the cycle repeats many times, assigning null prevents 'object is frozen' errors.
And of course, there was a lot of work with managing single BGW instance, queuing tasks etc.
(Currently I'm using ImagesContainer class defined also in my program that has two BitmapImage properties. I use it to receive preloaded images from backgroundworker. )
imgNext is a public variable defined in MainWindow. (main thread)
void bwImgLoader_DoWork(object sender, DoWorkEventArgs e)
{
backgrLoadNextPrevList list = e.Argument as backgrLoadNextPrevList;
ImagesContainer result = new ImagesContainer();
if (list.HasNextPath) result.imgPrev = PrepareImage(list.NextPath);
if (list.HasPrevPath) result.imgNext = PrepareImage(list.PrevPath);
e.Result = result;
}
void bwImgLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ImagesContainer result = e.Result as ImagesContainer;
if (result.imgNext != null)
{
setNextDelegate s = new setNextDelegate(setNext);
object[] t = { result.imgNext };
imgNext.Dispatcher.Invoke(s, t);
}
// do not take into account this line, just ignore it.
//if (result.imgPrev != null) imgPrev = result.imgPrev;
}
public void setNext(BitmapImage b)
{
imgNext = b;
}
public delegate void setNextDelegate(BitmapImage b);
Freezing the bitmapimage helps only on the first background load(see the comment under the answer below). When I call BackgroundWorker second time, an errors occures that the object is frozen and cannot be modified. Is there a way to un-freeze it?
Or, is there any way to copy data from one thread to another without copying an attribution to thread?
UPDATED
Thanks everybody for answering!
In fact, I managed to solve this problem by creating a static BitmapImage inside App class.
Before using it, I do
App.iNext = null;
Then I load the actual image and freeze it, so this static property can be accessed from everywhere. When the cycle repeats many times, assigning null prevents errors.
And of course, there was a lot of work with managing single BGW instance, queuing tasks etc.
But these efforts were worth the result - I got +125% in performance!!! Thank everyone!
BitmapImage is Freezable so you can Freeze() it after loading it. This will permit access from any thread.
It's easiest to create all UI objects on the same thread. This includes any classes descending from DispatcherObject, such as BitmapImage.
On the UI thread - before creating the BGW - capture the result of TaskScheduler.FromCurrentSynchronizationContext. You can stick it in a private member of your class. e.g.:
private TaskScheduler ui;
public void InitiateBGW()
{
this.ui = TaskScheduler.FromCurrentSynchronizationContext();
this.bwImgLoader.RunWorkerAsync();
}
On the BGW, whenever you need to access BitmapImage functionality (creating them or modifying them), queue it to the TaskScheduler like this:
private BitmapImage PrepareImage(string path)
{
// This code runs in a BGW.
// Load underlying bitmap (non-UI)...
var bitmap = ..;
// Prepare the bitmap (non-UI)...
return Task.Factory.StartNew(() =>
{
var ret = new BitmapImage();
// Load "bitmap" into "ret"
return ret;
}, CancellationToken.None, TaskCreationOptions.None, this.ui);
}
Related
I am writing an application that depends on fast image manipulation. It might sound strange but I'm doing this C# and not in C++. So far this has not been a limitation, I can process an image realtime. While I do quite some complex things with the image and I do this under 30ms.
I changed the program to make sure that the image stream would never queue
by simply checking a boolean to check if a current frame is not being processed. Normally this wouldn't happen, but in some cases it did. For example when run the app in VS2010 debug mode, or when the PC is doing also other heavy tasks, and has less CPU resources.
In such case I would like to skip new frame processing, so processing them won't queue. In such cases it would be better to just work with last known data which is still being processed, and thus waiting would be the fastest method then to retrieve an answer.
So I started with something like:
private void Camera_FrameReady(object Sender, ImageEvent e)
{
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
}
This didn't workout, as I had hoped. And I think it has to do with the threading nature of events within the C# compiler. So then I tried to resolve it by de-registering and re-registering the Camera_FrameReady ready, but the camera takes to much time to restart, so that didn't workout.
Strangely now it seams to work with the code below but I'm not sure why it does.
private void Camera_FrameReady(object Sender, ImageEvent e)
{
Update_Image(e)
}
private void Update_Image(e)
{
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
}
This makes me wonder about how C# gets compiled. Does it work like that whenever Camera_FrameReady is called it has a "world view" of the current global values? Or that global variables are only updated after the processing of an event?
The first thing came in my head is that the Camera_FrameReady event blocks the acquisition thread. But that doesn't explain why the second solution works..
So if you want to process the images parallel to the acquisition thread, you should create a new thread for processing.
For example: When there is a new image, check if the processing thread is busy. If the processing thread is busy, you shouldn't wait or queue (like you wanted) but just skip this image. If the processing thread is waiting for work, store the image in a 'global' variable, so the processing thread can access it and signal the processing thread.
I made an example for you: (pseudo)
// the thread for the processing.
private Thread _processingThread;
// a signal to check if the workerthread is busy with an image
private ManualResetEvent _workerThreadIsBusy = new ManualResetEvent(false);
// request for terminating
private ManualResetEvent _terminating = new ManualResetEvent(false);
// confirm terminated
private ManualResetEvent _terminated = new ManualResetEvent(false);
// store the current image.
private Image _myImage;
// event callback for new images
private void Camera_FrameReady(object Sender, ImageEvent e)
{
// is the workerthread already processing an image? return.. (skip this image)
if (_workerThreadIsBusy.WaitOne(0))
return; // skip frame.
//create a 'global' ref so the workerthread can access it.
/* BE CAREFULL HERE. You might experience trouble with the instance of this image.
* You are creating another reference to the SAME instance of the image
* to process on another thread. When the Camera is reusing this
* image (for speed), the image might screwed-up. In that case,
* you have to create a copy!
* (personally I would reuse the image which makes the image not available outside the event callback) */
_myImage = e.Image;
// signal the workerthread, so it starts processing the current image.
_workerThreadIsBusy.Set();
}
private void ImageProcessingThread()
{
var waitHandles = new WaitHandle[] { _terminating, _workerThreadIsBusy };
var run = true;
while (run)
{
switch (EventWaitHandle.WaitAny(waitHandles))
{
case 0:
// terminating.
run = false;
break;
case 1:
// process _myImage
ProcessImage(_myImage);
_workerThreadIsBusy.Reset();
break;
}
}
_terminated.Set();
}
private void ProcessImage(Image _myImage)
{
// whatever...
}
// constructor
public MyCameraProcessor()
{
// define the thread.
_processingThread = new Thread(ImageProcessingThread);
_processingThread.Start();
}
public void Dispose()
{
_terminating.Set();
_terminated.WaitOne();
}
}
Your code is not multithreading safe
if (!IsImageReady) return; // global var
IsImageReady = false;
//... do stuff with the image
IsImageReady=true;
2 threads can read IsImageReady at the same time, see that it is true and both set it then to false. You might also get problems if the processor is reading IsImageReady from cache and not from memory. You can avoid these kind of problems with the Interlocked class, which reads and changes the value in one operation. It also ensures that the cache doesn't cause problems.
private int IsImageReady= 0;
private void Camera_FrameReady(object Sender, ImageEvent e){
int wasImageReady = Interlocked.Exchange(ref IsImageReady, 1);
if (wasImageReady ==1) return;
//do something
IsImageReady= 0;
}
}
Although I am not sure if that is your only problem. You might have also others. To be sure, you have to debug your code properly, which is very difficult when it involves multithreading. Read my article Codeproject: Debugging multithreaded code in real time how you can do it.
I am having following scenario that I need to show preview option in my application like what ms-word does. When we click the info option under File menu item, then preview of document is shown.
In the same way, I also want to show the preview of my data rendering part in my application when someone clicks File\Info panel. For this i have written a method which gets the preview or screenshots of my app but that method is taking some time So when somebody click on the File menu then application hangs for a while. So, i tried to call that method on different thread using background worker as well as normal thread mechanism. but the thing is that method I am calling on different thread it returns an image source object and when I try to access that object on run worker completed event of background worker, then it shows an exception like owner of this object is a different thread which means that returned image has been created on a different thread therefore I can't use it. So, what is the optimized way to get and use that image in my case.
Code tends to be like this.
public void ShowPreview()
{
ImageSource source =null;
var bgWorkerThread = new BackgroundWorker()
bgWorkerThread.DoWork +=(SENDER,ARGS)=> {
source = planView.GetPreviewImage();
}
bgWorkerThread.RunWorkerCompleted += (sender,args)=>
{
// Application crashes at this point
infoPanel.PreviewImage.source = args.Result as ImageSource;
}
}
you can use invoke or you could create a "storage class" (i think its called a singleton but I'm not sure) reuse the same instance across several classes and/or threads like this.
class Test
{
void main()
{
newThread nt = new newThread();
Storage store = new Storage();
nt.store = store;
Thread t = new Thread(new ThreadStart(nt.runMe));
t.Start();
}
}
public class newThread
{
public Storage store;
public void runMe()
{
store.someNum = 8;
}
}
public class Storage
{
public int someNum;
}
Usually, when you access controls in a Thread you end up with some cross thread exceptions. In my C# WinForms Application I have a picture box and a toolstriplabel which do not cause that exception. I don't understand why, can anybody explain this to me?
Here some code explanation:
In the main form I have a picturebox and a toolstriplabel. Also I have a reference to another Form, which has no controls and no additional source code. And then in the main form there is another object which works with a thread. This thread can raise three different events and the main form is subscribed to these three events.
Event1 causes the toolstriplabel to update (with some information from the thread).
Event2 causes the picturebox to update (with a new picture from the thread).
Event1 and Event2 work perfectly fine. I do not use any invoke methods, I directly change Text and BackgroundImage properties without cross thread exception.
Event3 though makes troubles. It is supposed to show the other form but I receive the cross therad exception. It works only if I use a BeginInvoke to show the form.
Why is that?
Edit:
The multithreading is done by an MJPEGStream object. I subscribe the NewFrame method of that MJPEGStream object.
public partial class Form1 : Form
{
private CAM cam;
private PeekWindow frmPeekWindow;
public Form1()
{
InitializeComponent();
cam = new CAM();
cam.NewImageMessageEvent += new NewImageEventHandler(cam_NewImageMessageEvent);
cam.DetectionEvent += new DetectionEventHandler(cam_DetectionEvent);
cam.FpsChangedMessageEvent += new FpsChangedEventHandler(cam_FpsChangedMessageEvent);
cam.DetectionThreshold = (float)this.numDetectionThreshold.Value;
frmPeekWindow = new PeekWindow();
// without the next two lines, frmPeekwindow.Show() won't work if called in an event
frmPeekWindow.Show();
frmPeekWindow.Hide();
}
void cam_FpsChangedMessageEvent(object sender, FpsChangedEventArgs e)
{
lblFPS.Text = string.Format("fps: {0:0.0}", e.FPS);
}
void cam_DetectionEvent(object sender, DetectionEventArgs e)
{
if (chkEnablePeakWindow.Checked)
{
if (frmPeekWindow.InvokeRequired)
{
frmPeekWindow.Invoke((MethodInvoker)delegate()
{
frmPeekWindow.Show();
frmPeekWindow.setImage(e.Image);
});
}
else
{
frmPeekWindow.Show();
frmPeekWindow.setImage(e.Image);
}
}
}
void cam_NewImageMessageEvent(object sender, NewImageEventArgs e)
{
picStream.BackgroundImage = e.Image;
}
}
And here's the CAM class:
class CAM
{
private object lockScale = new object();
private MJPEGStream stream;
private Bitmap image;
public event NewImageEventHandler NewImageMessageEvent;
public event FpsChangedEventHandler FpsChangedMessageEvent;
public event DetectionEventHandler DetectionEvent;
// configure (login, pwd, source)
public CAM()
{
this.stream = new MJPEGStream("...");
this.stream.Login = "...";
this.stream.Password = "...";
this.stream.NewFrame += new NewFrameEventHandler(OnNewFrame)
}
private void OnNewFrame(object sender, NewFrameEventArgs ev)
{
try
{
FpsChangedMessageEvent(this, new FpsChangedEventArgs(10));
// get image
image = ev.Frame;
NewImageMessageEvent(this, new NewImageEventArgs(new Bitmap(image)));
DetectionEvent(this, new DetectionEventArgs(new Bitmap(image)));
}
catch (Exception ex)
{
Console.Out.WriteLine(ex.Message);
}
}
}
You won't get cross thread exception, but it doesn't mean that this is a safe operation. There is always a possibility for your control to go unstable. You just don't know when it will happen.
See the following explanation from Microsoft.
http://msdn.microsoft.com/en-us/library/ms171728.aspx
Access to Windows Forms controls is not inherently thread safe. If you
have two or more threads manipulating the state of a control, it is
possible to force the control into an inconsistent state. Other
thread-related bugs are possible, such as race conditions and
deadlocks. It is important to make sure that access to your controls
is performed in a thread-safe way.
I have these three possibilites in mind:
The action is already dispatched to the gui thread.
The action doesn't need to be dispatched currently.
The action is somehow executed from the gui thread.
It's most likely number 3.
You don't necessarily always have to call BeginInvoke/Invoke. Sometimes the operation is running on the foreground thread, sometimes it is in the background.
Per the microsoft samples that are everywhere, You can SHOULD check to see if calling BeginInvoke/Invoke is required.
private void SetTextStandardPattern()
{
if (this.InvokeRequired)
{
this.Invoke(SetTextStandardPattern);
return;
}
this.text = "New Text";
}
Here is a nice microsoft article that has a sample:
http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx
and here is another article on how to "avoid" the pattern:
http://www.codeproject.com/Articles/37642/Avoiding-InvokeRequired
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(3 answers)
Closed 8 years ago.
I have a listview that contains file names. I have another listview that contains possible actions to rename these files. Finally I have a label that displays a preview of the result. When an object is selected in each of the lists I want to display the preview. You can select only one file but one or more actions. I use WPF/Xaml for my UI. I chose to perform my preview with a thread.
Here is a part of my code :
private Thread _thread;
public MainWindow()
{
InitializeComponent();
_thread = new Thread(DoWork);
}
public void DoWork()
{
while (true)
{
FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE
if (fileData != null)
{
string name = fileData.FileName;
foreach (var action in _actionCollection)
{
name = action.Rename(name);
}
previewLabel.Content = name;
}
Thread.Sleep(1000);
}
}
private void listViewFiles_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_thread.Start();
}
At run time I get the error "The calling thread cannot access this object because a different thread owns it." on the FileData fileData = listViewFiles.SelectedItem as FileData; line. Do you know what should I do ?
You can't modify or access UI from nonUI thread. So if you still want to use different thread first thing you need to do is to add some kind of model (for more info about binding and model try search for "wpf mvvm"), then bind you listViewFiles.SelectedItem to some property of this model this will allow you to access SelectedValue across threads. Second you need to separate all logic that changes UI to method or use lambda so in the end it can look like this:
public void DoWork()
{
while (true)
{
FileData fileData = Model.SelectedValue;
if (fileData != null)
{
string name = fileData.FileName;
foreach (var action in _actionCollection)
{
name = action.Rename(name);
}
this.Dispatcher.Invoke((Action)()=> //use Window.Dispatcher
{
label3.Content = fileData.FileName;
label4.Content = name;
});
}
Thread.Sleep(1000);
}
}
UPD. Some additional words about synchronizing with UI: in WPF every UI object inherits from DispatcherObject class. Thus all access to object of this type can be made only from thread in which this object was created, if you want to access DispatcherObject(DO) from another thread you need to use DO.Dispatcher.Invoke(Delegate) method, this will queue your code to DO thread. So in conclusion to run code in UI thread you need to use Dipatcher of any UI element in this case we use Dispatcher of Window (assume that code in window code behind).
Simple answer is that you can't do that: thread A cannot directly access winforms objects (controls) that thread B created.
In practice, you can use a delegate to run this safely on the other thread ala:
form.Invoke(new MethodInvoker(() => {
FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE
if (fileData != null)
{
string name = fileData.FileName;
foreach (var action in _actionCollection)
{
name = action.Rename(name);
}
previewLabel.Content = name;
}
}));
However, you may want to just
use a Background worker: http://msdn.microsoft.com/en-us/library/8xs8549b.aspx
In more detail at: http://weblogs.asp.net/justin_rogers/pages/126345.aspx
I am currently working on a home project for myself.
The program is written in C# using winforms.
The problem I'm currently experiencing is as followed:
I have a listview in my mainform called lvwGames
When I run the program without debugging, it runs fine.
However when I start with a debug, I get an error. This has something to do with the background worker thread.
Allow me to post some code to assist me.
private void MainViewLoad(object sender, EventArgs e)
{
RefreshGamesListView();
}
Nothing special here.
The reason I am calling RefreshGamesListView() is because I have to refresh on several occasions.
The method being called looks like this.
public void RefreshGamesListView()
{
pbRefreshGamesList.Value = 0;
bgwRefreshList.RunWorkerAsync();
}
So when the method is called, the background worker is called and runs the dowork method.
This one is quite big.
private void BgwRefreshListDoWork(object sender, DoWorkEventArgs e)
{
List<Game> games = _mainController.RetrieveAllGames();
int count = 1;
foreach (Game game in games)
{
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
li.SubItems.Add(game.Genre.name);
li.SubItems.Add(game.Publisher.name);
li.SubItems.Add(game.Platform.name);
li.SubItems.Add(game.CompletionType.name);
li.SubItems.Add(game.gameNotice);
lvwGames.Items.Add(li);
double dIndex = (double)(count);
double dTotal = (double)games.Count;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
count++;
bgwRefreshList.ReportProgress(iProgressPercentage);
}
}
When i run the code in debug, when the code is on lvwGames.Items.Add(li);
It gives me the following error:
Cross-thread operation not valid: Control 'lvwGames' accessed from a thread other than the thread it was created on.
I have absolutely no clue why.
I think it is code specific. But it can also mean I don't get the background worker completely, and specifically when to use it properly.
The reason I'm using it is because I'm loading a large large list from the database, I want to keep responsiveness in the UI when the list is loaded, and inform the users how far it is, using a progress bar.
If any code is missing, or you actually understand why this is happening PLEASE explain me why in this case its causing the error. You don't need to fix it for me. I just want to know WHY it's caused.
Thanks for taking the time to read this post. I hope to be able to continue using the debugger soon. :)
You need to call Conrol.Invoke when accessing visual controls from background threads.
if (_lvwGames.IsHandleCreated) {
Action addGameToList = () => {
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
....
_lvwGames.Items.Add(li);
};
if (_lvwGames.InvokeRequired) {
_lvwGames.Invoke(addGameToList);
} else {
addGameToList();
}
}
From Manipulating Controls from Threads
...For example, you might call a method that disables a button or
updates a display on a form in response to action taken by a thread.
The .NET Framework provides methods that are safe to call from any
thread for invoking methods that interact with controls owned by other
threads. The Control.Invoke method allows for the synchronous
execution of methods on controls...
This is because you're attempting to access a UI control (lvwGames) from a background thread. The way to make it work requires you to marshal the information back to the main UI thread and update the control from there:
private void BgwRefreshListDoWork(object sender, DoWorkEventArgs e)
{
List<Game> games = _mainController.RetrieveAllGames();
int count = 1;
foreach (Game game in games)
{
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
li.SubItems.Add(game.Genre.name);
li.SubItems.Add(game.Publisher.name);
li.SubItems.Add(game.Platform.name);
li.SubItems.Add(game.CompletionType.name);
li.SubItems.Add(game.gameNotice);
// This is the new line you need:
lvwGames.Invoke(new MethodInvoker(delegate { lvwGames.Items.Add(item) }));
double dIndex = (double)(count);
double dTotal = (double)games.Count;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
count++;
bgwRefreshList.ReportProgress(iProgressPercentage);
}
}
Normally you would check the InvokeRequired property first as mentioned in other answers, but there is really no need if you are always calling it from the background thread. Your DoWork method will always require an invoke call, so you might as well just go ahead and write it like that.
This happening cause, just like compiler cliams, you are going to update UI control content from another thread. You can not do that, as UI control can be updated only within main thread.
Please have look on this SO answer with example code provided:
Invoke from another thread
The background worker is not working properly if you run in debug mode in studio. If you have calls that use the windows handle to retrieve messages, then they will fail. If you for instance have a progressChanged event handler and this changes a text in a textbox that might fail.
I had this scenario: A Form that has a background worker. If I just start the worker without getting a dialog box up first then it works ok. If I show a dialog and then start the background worker then it fails. When I run the program normally it does not fail. It is somehow the debug environment that destroys the link between the events and the foreground window. I have changed my code to use invoke, and now all works both in when running in release and when I debug.
Here is a link explaining what can be done to make a program thread safe.
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx
I did not do the same as the sample to microsoft. I made delegates, assigned to the functions I needed to run. and called invoke on them.
sample pseudo code:
class MyClassWithDelegates
{
public delegate void ProgressDelegate( int progress );
public ProgressDelegate myProgress;
public void MyProgress(int progress)
{
myTextbox.Text = ..... ; // this is code that must be run in the GUI thread.
}
public MyClassWithDelegates()
{
myProgress = new ProgressDelegate(MyProgress);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Invoke( myProgress, e.ProgressPercentage );
}
}
All code that potentially have to be run in the GUI thread of the application must be Invoked to be safe.