BackgroundWorker: Childs of Argument-Object - c#

I am working on a WPF Application that was running smooth until I added threadding. I wanted to ease the saving/autosaving process by putting it into a BackgroundWorker so my UI is not blocked while saving occours.
Think of my App as a custom photobook maker.
Lets assume my UI consists of several Image Objects. The Source for those images lies within a custom PhotobookImageObject because each selected Image also contains additional Metadata.
PhotobookImageObject
public class PhotobookImageObject
{
public BitmapSource source { get; set; }
public String unimportantMetadata{ get; set; }
}
When I want to save, I want to save the complete Photobook. For simplicity:
Photobook
public class Photobook: INotifyPropertyChanged
{
public List<PhotobookImageObject> Photos{ get; set;}
public String otherMetaData { get; set;}
}
My Saving process worked when not using Threads. But ever since Im running it in a BackgroundWorker I can not access the PhotobookImageObjects in the list anymore.
Now I know the Thread for Saving can not Acces Objects from different Threads. This is why I am using a custom Class to Push the object into the thread of the BackgroundWorker. I found this solution here: How do you pass a List<> of Lists<> to a background worker?
Here is the acutal code:
Setting up the Worker:
private static BackgroundWorker saveWorker = new BackgroundWorker();
private static void saveWorkerExec(Photobook book, String Location, bool notAuto)
{
saveWorker.DoWork += doWork;
saveWorker.WorkerSupportsCancellation = true;
saveWorker.RunWorkerCompleted += (s, o) =>
{
Helper.Message("Photobook saved");
if (o.Error != null)
{
MessageBox.Show("There was an error while saving! \n\n" + o.Error.ToString());
}
};
BGObj obj = new BGObj
{
bk = book,
Loc = Location,
not = notAuto
};
saveWorker.RunWorkerAsync(obj);
}
The custom class I use to transfer the Data:
public class BGObj
{
public Photobook bk { get; set; }
public String Loc { get; set; }
public bool not { get; set; }
}
And the actual part where the BackgroundWorker should receive the class into his own Thread:
private static void doWork(object sender, DoWorkEventArgs e)
{
BGObj received = e.Argument as BGObj;
Photobook book= received.bk;
String Location = received.Loc;
bool notAuto = received.not;
//this function can not Access the books.Photos.last().source for example.
SaveProjectToContainer(book, Location, notAuto);
}
I am still receiving a System.InvalidOperationException when I try to access the BitmapSource of the PhotobookImageObject in the Photos List in Photobook.
My assumption: the BGobj I am creating is only referencing the actual Photobook so the data of its members is still resting in the wrong thread. How on earth can I make sure all submembers of my objects are actually passed to the Thread where I want to process them? Or am I wrong here and its something else?
Thank you for your time.

Since nobody could help me with the issue I followed Theodors approach and switched to a more modern approach using Async/Await.
From my understanding this is not making the actions run in the background but still freeing the UI thread and running the await" tasks "inbetween" when the thread has capacity free. This allows me to access the UI-elements and still stop the application from freezin a bit while autosaving.
If someone needs a few hints how to solve this think of it like this:
public static void NotMain()
{
// queue following function. void Main for example would continue running after this.
await do_stuff_in_between(var object);
// Stuff after await will only happen if the function is done but UI is not blocked
Console.WriteLine("saving done");
}
public static async Task do_stuff_in_between(var object)
{
// do stuff with object or whatever you want.
}

Related

The UI freezes until the method is finished. How can not freeze?

I'm coding 'Waiting for login' in the app.
public struct Member
{
public bool IsOpened, IsLogIn;
public string Title, Name;
}
private static void WaitForLogin(ref Member member)
{
while (member.IsOpened)
{
if (IsLoggIn() == true)
{
member.Title = "Welcome to App Centrel";
member.Name = "Omer";
member.IsLogIn = true;
break;
}
System.Threading.Thread.Sleep(1000);
}
}
Using the non-freezing Task, Thread, Async Etc... codes, Time problem occurs due to the ref, out in the parameter.
How does the method not freeze until finished using out, ref parameter?
External app is the not logged in. started freezing in my UI.
I wanted to change the 'mem' variable the time when logged in in the IsLoggIn() method
Once again, why you are using struct? Why not like this?
public class Member
{
public bool IsOpened { get; set; }
public bool IsLogIn{ get; set; }
public string Title{ get; set; }
public string Name{ get; set; }
}
private static async Task WaitForLogin(Member member)
{
while (member.IsOpened)
{
if (IsLoggIn() == true)
{
member.Title = "Welcome to App Centrel";
member.Name = "Omer";
member.IsLogIn = true;
break;
}
await Task.Delay(1000);
}
}
Then you should be able to use it like this
private async void button1_Click(object sender, EventArgs e)
{
Member asD = new Member();
asD.IsOpened = true;
await WaitForLogin(asD);
MessageBox.Show("Logged In. Starting Methods");
}
Thread.Sleep(1000) will suspend the current (UI) thread. This is rarely a good idea, especially on the UI thread. Also note that your example code is probably not safe. I would assume that you are modifying the IsOpened field from another thread, and this is not safe without at least marking the field as volatile. But just use a full lock if you are unsure about the level of synchronization needed.
I do not see that the ref has any real effect on the UI freezing. But I would in general recommend against mutable structs. Just use a class with properties instead.
The simplest possible workaround would be to replace the sleep with a Task.Delay and mark the method as async. This will internally be similar to starting a timer that checks for the login. But be careful with async void functions, since they can lose exception if you are not careful. Prefer to return a task for async functions, unless it has to be void, like an event-handler.
A better solution will be to let whatever component doing the login to send an event. This might be a regular event, or it might be thread-safe event, or a waithandle that may be triggered from a separate process if named. You can also use a task to signal the completion of some login process. But it is difficult to tell exactly how this should be done without more information about the internals of the system.
Regardless of the option you pick, you should probably show a modal UI dialog while waiting for login, to prevent any other interaction with the UI while waiting, while still allowing the UI to be responsive.
For example using a task to signal login and winforms for the UI
public static Task ShowDialogUntillLogin(Task loginTask){
var myForm = new MyForm();
loginTask.ContinueWith(t => myForm.Invoke(() => myForm.DialogResult = DialogResult.OK));
myForm.ShowDialog();
return loginTask;
}
This should show the form until the task is set as complete. When this happens the dialog will be closed and the method returns. Since it blocks inside the ShowDialog method UI messages will still be processed, and the UI remain responsive, but the user can only do stuff in MyForm.

Is a lock statement needed within a class derived from BackgroundWorker?

I have a class that inherits from BackgroundWorker to do some specific stuff on a remote server. I've added properties for this class to store information needed for the job to complete. Example:
public class GenerateFileWorker : System.ComponentModel.BackgroundWorker
{
public string LocalFileName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public GenerateFileWorker() {}
public GenerateFileWorker(string username, string password, string localFileName)
{
Username = username;
Password = password;
LocalFileName = localFileName;
}
protected override void OnDoWork(DoWorkEventArgs e) {
// ...
}
I know lock is needed to safely access objects outside the class, but what about within? Do I need it when accessing the properties of the current instance within OnDoWork()?
It's not a question of what class you're inheriting from. It's a question of whether multiple threads may concurrently read or modify properties or fields so that they interfere with each other, or one thread reads while another is in the middle of updating something. That's when you would need a lock (or some other mechanism) to ensure that such conflicts don't occur. (That's an oversimplification for brevity.)
From the documentation:
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread.
The idea is that the UI thread only interacts with the background thread by canceling it, getting progress reports from it, or being notified that it has finished or failed. It doesn't directly access the variables (state) used within the process.
One thing in your class that stands out is this:
public string LocalFileName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
Because those are read/write properties it's possible that the UI thread could update them while the background thread is using them. I imagine that's probably not your intent. Do those properties need to be writable? Or do they even need to be properties at all? (If they don't need to be properties, do you need to inherit?)
Perhaps you can initialize variables containing those values at the beginning of the background process. Now those variables are private within the method executed by the background process, which means that it's not possible for the UI thread or any other thread to interact with them.

How to clear a class after it is no longer being by any thread

Say i have a Map class, which has some data used for ready only, and there are multiple workers (threads) using this class at the same time.
If i wanted to clear that map instance (erase it's data) when it is no longer being used by any worker, how would i do that efficiently in a thread safe way?
Something like this:
public class Map
{
public static Map activeMap;
public int used;
public void BeginWork()
{
System.Threading.Interlocked.Increment(ref used);
}
public void EndWork()
{
System.Threading.Interlocked.Decrement(ref used);
if(this != activeMap && used == 0)
{
Erase();
}
}
// This method is only called on the main thread.
public static void ChangeActiveMap(Map newActiveMap)
{
Map previousMap = activeMap;
activeMap = newActiveMap;
if (previousMap.used == 0)
{
previousMap.Erase();
}
}
private void Erase()
{
// Erase Map data here.
// Put Map into a pool for later use and prevent it from going to GC.
}
}
public class Worker
{
private Map map;
public void BeginWork()
{
Map.activeMap.BeginWork();
map = Map.activeMap;
// Do work here with map data.
map.EndWork();
map = null;
}
}
If the map gets erased while a worker is still using it, the worker will work on blank map data, which will lead to error. I get the feeling that the code above will not work properly. It would really be a plus doing this without using locks.
EDIT : Map data is too expensive to go into GC, the idea with the Clear method is to recycle it and put it into a pool for later use without ever going into GC.
Maybe the code works assuming that it will only get cleared if it is no longer the activeMap, because new workers will only start a new work with the activeMap ?
EDIT: Added the ChangeActiveMap method to the code. I think is method is also a problem for multithreading.

Design pattern for reporting/monitoring progress of long processes

Anyone can suggest a good Design Pattern for reporting/monitoring status/progress of long processes.
Basically, I have a codebase that receives a "data-context" object:
public class DataContext : IDataContext
{
pulbic Dictionary<string, objects> Properties { get; private set; }
// Additional properties removed for simplicity...
}
Based on the provided context, a Task (not TPL-Task) object is created, with various subtasks.
During execution, the DataContext object is passed to the various sub-tasks, which can retrieve or update it.
For example, let's say that the main task is a "Copy files" task. The DataContext will have properties like the SourceFolder and TargetFolder, and perhaps a FilterFiles property (e.g. *.docx). Our main task will be a CopyFilesTasks, and it will have a "pipeline" of subtasks - Scan Folders, Scan Files, Filter Files, Copy Files, etc....
What I am looking for, is the best way to allow the task/sub-tasks to report their progress to the caller/executer.
In our example above, the changes in progress might be just "Copied file ABC.docx...", or perhaps something a bit more "complex", like "Scanning folder XYZ..."
I have considered the following options:
INotifyPropertyChanged: add a "Progress" property to DataContext
public string Progress { get; set { _progress = value; RaisePropertyChanged("Progress"); }
and have the code that created the DataContext object register to the PropertyChanged event. However, this seems like a too-simplistic approach...
ILog (using whatever logging framework you prefer): use an ILog instance in the various tasks/sub-tasks, and have the main-task executioner add it's own listener to the logging framework.
However this seemed like bending the logging mechanism to do things it was not supposed to do.
Udi Dahan's DomainEvents: The executioner of the task can regard the DataContext as a "domain", and therefore we can try to implement an "EventHandler" for a "ProgressChanged" event. In theory, this can be even used for more refined events, that happen in specific sub-tasks... But once again, it feels like forcing the concept...
My concerns include things like:
Progress might not be the only "event" that needs to be monitored - in our example above, we might want things more defined, like FolderHandled, FileCopied, etc., but we might not know the exact events when executing the tasks (remember - the subtasks are created based on the DataContext, and might result in different tasks being executed).
The context of running the tasks is not yet defined. For now, I'm just planning to run the tasks from the command-line application, so outputting to the command-line is needed for debugging. Later on, when I move this to a service, I might want to have a "listener" update a database with the task's progress (for example).
You can declare arguments for each possible operation type, say FileOperationEventArgs for file operation, DatabaseUpdateEventArgs for database operation etc.
public class FileOperationEventArgs : EventArgs
{
public readonly string SourceFolder;
public readonly string TargetFolder;
public FileOperationEventArgs(string sourceFolder, string targetFolder)
{
SourceFolder = sourceFolder;
TargetFolder = targetFolder;
}
}
public class DatabaseUpdateEventArgs : EventArgs
{
public readonly int RowsUpdated;
public DatabaseUpdateEventArgs(int rowsUpdated)
{
RowsUpdated = rowsUpdated;
}
}
OperationProgress class declares events for each operation type.
public class OperationProgress
{
public event EventHandler<FileOperationEventArgs> FileCopied;
public event EventHandler<DatabaseUpdateEventArgs> DatabaseUpdated;
public void OnFileCopied(FileOperationEventArgs a)
{
if(FileCopied != null)
FileCopied(this, a);
}
public void OnDatabaseUpdated(DatabaseUpdateEventArgs a)
{
if (DatabaseUpdated != null)
DatabaseUpdated(this, a);
}
}
OperationProgress will be specified when DataContext is created.
public class DataContext : IDataContext
{
public Dictionary<string, object> Properties { get; private set; }
public OperationProgress Progress { get; private set; }
public DataContext(OperationProgress progress)
{
Progress = progress;
}
}
Subtask implementation can update the progress.
public class FileCopySubTask
{
public void Execute(DataContext context)
{
context.Progress.OnFileCopied(new FileOperationEventArgs("c:/temp1", "c:/temp2"));
}
}
Consider BackgroundWorkers.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
They have their own reportprogress event on a separate UI thread.

InteropBitmap synchronization

WPF InteropBitmap can be created from shared memory, i.e.
Imaging.CreateBitmapSourceFromMemorySection()
In this case, we can update shared memory in another thread or process, and then after updating, calling InteropBitmap.Invalidate() to present the changes.
From the WPF source code, InteropBitmap is just a wrapper of IWICBitmap, but it doesn't expose IWICBitmap::lock which is used for exclusive writing.
So, how do I sync writing and reading of WPF InteropBitmap?
Updating occurs in user's thread.
Reading always occurs in WPF internal render thread via IWICBitmapSource::CopyPixels
Thanks
You can create a WrapperClass which exposed a lock object and the methods to manipulate the Image. Is some work but would work 100%
something like:
class InteropBitmapSyncWrapper
{
public InteropBitmapSyncWrapper(InteropBitmap wrappedBitmap)
{
WrappedBitmap = wrappedBitmap;
this.Lock = new Object();
}
public InteropBitmap WrappedBitmap
{
get;
set;
}
public Object Lock
{
get;
private set;
}
}

Categories