Visit domain model with second thread - c#

My domain model is large tree structure that is modified by application. I would like to implement search in BackgroundWorker (separate thread to not block the UI).
Currently tree structure is implemented with ObservableCollection, that cannot be enumerated while it is modified, so my search will fail if user modifies tree while I am searching through it.
What is elegant solution for this problem? My requirements: do not block user from doing anything (operation should be async), search on separate thread (to speed things up).

Here is one way I can think of that you can achieve what you need:
When writing, use lock, create a copy of the collection, add to the copy and then re-assign the collection to the copy.
Here is some code so you can test the above method. Create a form with a ListBox and a Button. While the list is being searched on a thread, you can add items to the list using the button.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace WindowsForms {
public partial class Form1 : Form {
object key = new object();
private List<string> items;
public Form1() {
InitializeComponent();
items = new List<string>();
for( int i = 0; i < 100000; i++ ) {
this.items.Add( i.ToString() );
}
this.listBox1.DataSource = this.items;
}
private void Read() {
foreach( var thisItem in this.items ) {
if (thisItem.ToString() == "100000" ) {
MessageBox.Show( "Found" );
}
else {
Thread.Sleep( 100 );
}
}
}
private void buttonStation2_Click(object sender, EventArgs e) {
lock( this.key ) {
var copy = new List<string>( this.items );
copy.Add( "1000001" );
this.items = copy;
}
}
private void Form1_Shown(object sender, EventArgs e) {
Thread reader = new Thread( Read );
reader.Start();
}
}
}
You may also want to make the collection variable volatile so a cached version is not used and you always get the latest when reading. However, you really need to know what the volatile keyword does before using it so that is why I did not use it in my code and left it up to you to decide. Also, other SO users may chime in and offer their advice using volatile in the comments to this answer if they wish.
private volatile List<string> items;

Related

C# Accessing form control from different thread

I've been looking at https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls and other Stack Overflow questions for a good long while now to figure out how to use thread-safe methods to access a ListView controls from different threads.
Here's how I want to implement parallel tasks in my program:
I call four different methods in parallel with:
Parallel.Invoke(ProcessLow, ProcessMed, ProcessHigh, ProcessSprint);
Each method searches through the same collection (data[i].Knots) with a for loop and looks for a different range of values within that collection, then if one of the methods finds an appropriate value within the range it's looking for it adds the time and knots (data[i].Time, data[i].Knots) to its respective ListView (the methods write to lstvLow, lstvMed, lstvHigh and lstvSprint respectively). At the moment it's just throwing the exception for non-thread safe code. Also will it break if I have different threads just reading off the same collection? (if so, how can I work around this?)
tldr: Parallel processing is new to me, how do I make a thread-safe call to a windows form control.
And also if you can, point me in the direction of some good reading other than msdn for Parallel tasking.
edit: this is with winforms
To make thread safe call. use Control.Invoke(); method. Assuming you have instance of ListView mylistView; you can write:
object result = mylistView.Invoke(new Action(() => mylistView.DoSomething()));
As I understand, you are new to multitasking. I hope my case study will help you. Create a windows form with next controls:
startButton, stopButton as Button
minTextEdit, maxTextEdit as TextEdit
listListView as ListView
For startButton and stopButton use the appropriate methods: startButton_Click and stopButton_Click.
Full the code below:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Thread0
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private static readonly Random _random = new Random();
private List<int> lst = new List<int>();
private bool isRun = false;
private void startButton_Click(object sender, EventArgs e)
{
isRun = true;
stopButton.Enabled = true;
startButton.Enabled = false;
var tskMain = Task.Run(() =>
{
for (int i = 0; i < 8; i++)
{
var tsk1 = Task.Run(() =>
{
while (true)
{
int max = 0;
int min = Int32.MaxValue;
lock (lst)
{
int num = _random.Next(1, 1000000);
lst.Add(num);
foreach (var x in lst)
{
if (x > max) max = x;
if (min > x) min = x;
}
listListView.BeginInvoke(new Action(() => listListView.Items.Insert(0, num.ToString())));
}
maxTextBox.BeginInvoke(new Action(() => maxTextBox.Text = max.ToString()));
minTextBox.BeginInvoke(new Action(() => minTextBox.Text = min.ToString()));
if (!isRun) break;
Thread.Sleep(100);
}
});
}
});
}
private void stopButton_Click(object sender, EventArgs e)
{
isRun = false;
stopButton.Enabled = false;
startButton.Enabled = true;
}
}
}
When you click on the Start button, the stream create and run tskMain thread, which creates 8 more threads. In each of them, an integer is added to the list of values lst, and the search for the maximum and minimum values. The new number is also added to the listListView, and the maximum and minimum value in the corresponding minTextEdit and maxTextEdit.
For work it is convenient to use lambda expression.
lock(lst) ... blocks work with the list of values. One action per time, so that there are no exceptions.
And the BeginInvoke method allows you to call methods from threads for form elements that are in the main form stream. The Action is used to "transform" the lambda expression into a delegate method.
Inside each thread, the variable IsRun is checked, if its value becomes false, the thread execution stops.
Well, to ensure that everything is not very quickly use .Sleep

C# WPF ModelVisual3D creation takes too long and cannot be done on separate thread

I have a WPF project (VS2010, .NET4.0) in which I create a rather big ModelVisual3D object (read from custom format STL file, process info, create mesh, etc.) This takes about 3-4 sec. to be created and another 2-3 sec. to do a mainViewport.Children.Add(ModelVisual3D).
I do this all in a custom class and call this method:
class My3DModel
{
...
public MyModelVisual3D createModelVisual3D(MyTypes tType, int tNumber)
{
this.myModelVisual3D = new MyModelVisual3D(tType, tNumber);
for (int i = 0, j = 0; i < this.Triangles.Length; i++)
{
this.mesh.Positions.Add(this.Triangles[i].Vertex1);
this.mesh.Positions.Add(this.Triangles[i].Vertex2);
this.mesh.Positions.Add(this.Triangles[i].Vertex3);
this.mesh.Normals.Add(this.Triangles[i].Normal);
this.mesh.Normals.Add(this.Triangles[i].Normal);
this.mesh.Normals.Add(this.Triangles[i].Normal);
this.mesh.TriangleIndices.Add(j++);
this.mesh.TriangleIndices.Add(j++);
this.mesh.TriangleIndices.Add(j++);
}
this.model3DGroup.Children.Add(new GeometryModel3D(this.mesh, material));
this.myModelVisual3D.Content = this.model3DGroup;
return this.myModelVisual3D;
}
}
The return value is also a custom class I created:
class ToothModelVisual3D : ModelVisual3D
{
//VARIABLES
private MyTypes myType;
private int number;
//OPERATORS
public MyTypes MyType
{get { return myType; } set { myType = value; }}
public int Number
{get { return number; } set { number = value;}}
public ToothModelVisual3D() { }
public ToothModelVisual3D(MyTypes tType, int tNumber) { MyType = tType; Number = tNumber; }
}
All I want to do is the following once in the beginning of the program:
{
My3DModel myModel;
myModel = new My3DModel();
myModel.readFileBytes("C:\\registered\\" + 1 + ".stl");
myModel.loadTriangles();
mainViewport.Children.Add(myModel.createModelVisual3D(MyTypes.Sometype, 1);
}
If I do it on the main thread the UI hangs. If I do it on a worker thread and invoke mainViewport.Children.Add(...) it says it cannot access the resourses created on that worker thread. Help?!
From what I understand I've reached a point where I have two threads and resources belonging to each of them (mainViewport => UIThread & myModel => WorkerThread). Neither thread can access directly the other's resource but creating and using myModel on the UIThread makes it hang... All I want to do is have enough responsiveness from the UI, so the user may minimize the program while waiting for it to load the models, nothing more. How can I do that? Is there a way to do all the CPU heavy work on the UIThread, so no resource conflicts arise and have a worker thread that only handles UI for that time?
PS: I've tried with Thread, BackgroundWorker & Task<TResult> classes. Results were similar if not to say the same.
PPS: The full version will load massive models which will load more than 30-40 sec...
I recently came across the same issue when porting an XNA application to WPF.
In my case I partially resolved this by using a background thread to load the positions, normals, and indices from file. Then in that same thread, construct a memory stream containing XAML for the Model3DGroup with the GeometryModel3D and MeshGeometry3D.
Then, in the UI thread, once the memory stream is available, load the model...
Model3DGroup model = System.Windows.Markup.XamlReader.Load(memoryStream) as Model3DGroup;
There is still a delay, but as file access is done in a background thread, it is not as severe.
Sorry for the late answer, but I actually managed to workaround the problem long time ago the following way:
delegate void myDelegate();
private void fileOpenButton_Click(object sender, RoutedEventArgs e)
{
try
{
Thread ViewportLoaderThread = new Thread(loadViewportItemsAsync);
ViewportLoaderThread.IsBackground = true;
ViewportLoaderThread.Start();
}
catch (Exception err) { UtilsProgram.writeErrorLog(err.ToString()); }
}
private void loadViewportItemsAsync()
{
try
{
//TRY to browse for a file
if (!browseForFile()) return;
Dispatcher.Invoke(new Action(() => { myStatusBar.Visibility = System.Windows.Visibility.Visible; menuItemHelpDemo.IsEnabled = false; }), null);
//Load file, unpack, decrypt, load STLs and create ModelGroup3D objects
UtilsDen.DenModel = new DenLoader(UtilsDen.Filename, UtilsDen.Certificate, UtilsDen.PrivateKey, this);
//Load the models to viewport async
myDelegate asyncDel = new myDelegate(sendModelsToViewportAsync);
this.Dispatcher.BeginInvoke(asyncDel, null);
}
catch (Exception err) { MessageBox.Show(UtilsProgram.langDict["msg18"]); UtilsProgram.writeErrorLog(err.ToString()); }
}
private void sendModelsToViewportAsync()
{
for (int i = 0; i < UtilsDen.DenModel.StlFilesCount; i++)
{
//Add the models to MAIN VIEWPORT
ModelVisual3D modelVisual = new ModelVisual3D();
GeometryModel3D geometryModel = new GeometryModel3D();
Model3DGroup modelGroup = new Model3DGroup();
geometryModel = new GeometryModel3D(UtilsDen.DenModel.StlModels[i].MeshGeometry, UtilsDen.Material);
modelGroup.Children.Add(geometryModel);
modelVisual.Content = modelGroup;
mainViewport.Children.Add(toothModelVisual);
}
}
The key was to use the this.Dispatcher.BeginInvoke(asyncDel, null); as it works on the main thread, but does not lag it, because it is executed asynchronously.
Using a delegate still appears to introduce a lag on the UI, a better solution is create the model in a worker thread and then freeze it. The model can then be cloned by the UI thread without the annoying exception. This works for me with models which take 25 seconds or more to load. The only issue I've found with this is that it doesn't work if the model contains a texture.

Disposed Forms with a Base and threading returns null for progress bar

I have a base form that I use when calling 2 forms. Previously when calling the forms I didn't dispose of them, but I have found that reusing them, they would stay in memory and not get collected. So I have instead used a using statement instead to clear the memory, and all my problem are fixed.
But now a new problem arises, one that I had previously when testing my app with mono on Linux. I though it might be a mono specific problem, but since adding the using statement the same thing happens on my Windows machine. So it might just be that the Garbage Collector on Mono is different and was disposing properly of my forms.
Here is my problem I have a thread that I start to extract files in the background And I have progress bar telling me the progress, before using the dispose if I closed the form and reopened it my files extracted correctly and the progress bar was working fine. But now they work fine the first time, but if I reopen the form or the other one that has the same base, the extraction is not working, no files are extracted because I have a null exception when reporting the progress.
private void ExtractFiles()
{
Zip.ExtractProgress += new EventHandler<ExtractProgressArgs>(Utils_ExtractProgress);
Thread t = new Thread(new ThreadStart(Zip.ExtractZip));
t.IsBackground = true;
t.Start();
FilesExtracted = true;
}
void Utils_ExtractProgress(object sender, ExtractProgressArgs e)
{
UpdateProgress(e.Pourcentage);
}
private delegate void UpdateProgressDelegate(int Pourc);
private void UpdateProgress(int Pourc)
{
lock (this)
{
if (Progress.ProgressBar.InvokeRequired)
{
UpdateProgressDelegate del = new UpdateProgressDelegate(UpdateProgress);
Progress.ProgressBar.BeginInvoke(del, Pourc);
} else
{
Progress.Value = Pourc;
}
}
}
This code is in my BaseForm, the Progress control isn't null, but all of it's properties have null exceptions. So when checking if Invoked is required it raises an Null exception.
Here is my Zip.Extract method
public static event EventHandler<ExtractProgressArgs> ExtractProgress;
static ExtractProgressArgs Progress;
internal static void ExtractZip()
{
try
{
using (ZipFile zip = ZipFile.Read(Variables.Filename))
{
Progress = new ExtractProgressArgs();
Progress.TotalToTransfer = Convert.ToInt32(zip.Sum(e => e.UncompressedSize));
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
Old = 0; New = 0;
foreach (ZipEntry item in zip)
{
item.Extract(Variables.TempFolder, ExtractExistingFileAction.OverwriteSilently);
}
}
} catch (Exception)
{
}
}
static long Old;
static long New;
static void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
{
New = e.BytesTransferred;
Progress.Transferred += New - Old;
Old = e.BytesTransferred;
if (ExtractProgress != null)
{
ExtractProgress(e.CurrentEntry, Progress);
}
} else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
{
Old = 0;
}
}
Might be because my Zip.Extract is static? I have almost no knowledge of multi-threading, like synchronization, etc.
The short answer is yes, some of your problems are due to the static nature of those operations.
You should be able to resolve the problem by removing the static declarations from your Zip class and then creating an instance of it as needed.

How to use effective caching in .NET?

i try to use effective caching but i face to face a problem. For example; i have 5 user they have used my app. user1,2,3,4 only fill grid by searcing(Caching is run!!!). on the other hand user5 adding new row. i want to refresh my cach data when adding new row. i read Multi threading to do that
code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using System.Collections;
namespace WebApp.Caching.Threading
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
FillCache();
}
void FillCache()
{
using (var myCtx = new DataClasses1DataContext())
{
if (!(FlyAntCache.Exists("test")))
{
List<Table_1> toolStoreList = myCtx.Table_1s.ToList();
FlyAntCache.Add(toolStoreList, "test");
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
WaitCallback method1 = new WaitCallback(ControlAllChanging);
bool isQueued = ThreadPool.QueueUserWorkItem(method1, new ManualResetEvent(false));
}
protected void ControlAllChanging(object state)
{
if (FlyAntCache.Exists("test"))
{
using (var myCtx = new DataClasses1DataContext())
{
List<Table_1> list;
list = myCtx.Table_1s.ToList();
List<Table_1> listCache = FlyAntCache.Get<List<Table_1>>("test");
bool IsIntersect = list.Except(listCache).Count() > 0;
if (IsIntersect)
{
FlyAntCache.Clear("test");
FillCache();
}
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
// Search
using (var myCtx = new DataClasses1DataContext())
{
var Qry = myCtx.Table_1s.
FromCache<Table_1>("test").
AsQueryable().Where(t => t.ad == TextBox1.Text.Trim());
GridView1.DataSource = Qry;
GridView1.DataBind();
}
}
}
}
My Scenario:
LOOK please :http://i53.tinypic.com/20pdc41.png
i really control if another user change my data, i must refresh my cache. is there any sensitivity to CAPTURE any new changing update new row save. for example :
1) i must capture new update . this mechanizm must run when changes occurs
2) i must capture new save. this mechanizm must run when new row adds
I'm still not quite sure what you're asking. My best guess is it sounds like you're trying to let a cache know when its data is stale.
Most caching implementations have this built in. Basically, you can expire a cache item (usually be removing it from the cache) when it has been updated.
For example, if you're just using the plain old built in caching that comes with ASP.net:
private static Cache Cache;
public void AddItem(string data)
{
//Do a database call to add the data
//This will force clients to requery the source when GetItems is called again.
Cache.Remove("test");
}
public List<string> GetItems()
{
//Attempt to get the data from cache
List<string> data = Cache.Get("test") as string;
//Check to see if we got it from cache
if (data == null)
{
//We didn't get it from cache, so load it from
// wherever it comes from.
data = "From database or something";
//Put it in cache for the next user
Cache["test"] = data;
}
return data;
}
UPDATE I updated the code sample to return a list of strings instead of just a string. This should make it more obvious what is happening.
To reiterate, the GetItems() call retrieves a list of strings. If that list is in cache, the cached list is returned. Otherwise, the list is retrieved and cached / returned.
The AddItem method explicitly removes the list from the cache, forcing the requery of the data source.
Not sure but are you looking for events? You could set up events in your caching mechanism to fire when an update occurs.
Here is a googled example

Using a Background Worker - Update a ProgressBar on the progress of a Recursive Method

Below is a method that I want to ship off into a background worker but I am struggling how to do it based on how created my method. As you can it doesn't return anything which is ok but it expects a directoryInfo object everytime it is recalled.
private void getSizeForTargetDirectory(DirectoryInfo dtar)
{
// generate a collection of objects. files comes first and then directories.
foreach (Object item in collection )
{
if (item == file)
{
track the size of the files as you encounter.
}
else if (item == directory)
{
// found a new directory, recall the method. !!!
}
}
}
This is my first time using a background worker so I'm a little stuck, I tried implementing something thanks to the help found here but got stuck when I realised my method was recursive.
How do I display progress during a busy loop?
I implemented a doWork event handler method but noticed that i needed to somehow recall the method if I had more files and folders to process on lower sub levels.
I have a simple button click event handler that calls my 'getSizeForTargetDirectory()' method when the current selected node is a directory.
private void retrieveInfoButton_Click(object sender, EventArgs e)
{
// check to see if the path is valid
// reset the labels and textfields.
string fullPath = treeDrives.SelectedNode.FullPath;
string sNodesName = treeDrives.SelectedNode.Text;
if (directory) // Enter here if its a directory.
{
string parentPath = treeDrives.SelectedNode.Parent.FullPath;
DirectoryInfo[] dirArray = populateFoldersArray(parentPath);
for (int i = 0; i < dirArray.Length; i++)
{
if (dirArray[i].Name == sNodesName)
{
getSizeForTargetDirectory(dirArray[i]);
// do work !
Hopefully that explains what I am trying to do and how I am doing it. Question is how can i use the report progress feature of the background worker class when the bulk of the work I am trying to ship is coming from a recursive method.
Through early testing I noticed that my getSize method was incredibly efficient after a few tweaks and reported size information for the current supplied folder very quickley but then again I use quite a powerful dev machine so this may not be true for all users.
Thanks For Reading, Hope someone can help !!!
I think it is much simpler to use the built-in methods on either Directory or DirectoryInfo to obtain all directories, or files, using the recursive search option:
public partial class Form1 : Form
{
private Action<float> updateProgMethod;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
updateProgMethod = UpdateProgress;
}
private void GetDirectorySizeAsync(string path)
{
backgroundWorker.RunWorkerAsync(path);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
DirectoryInfo di = new DirectoryInfo((string)e.Argument);
di.GetTotalSize(ProgressCallback);
}
// Takes callbacks from the GetTotalSize() method
private void ProgressCallback(float p)
{
// Invokes update progress bar on GUI thread:
this.BeginInvoke(updateProgMethod, new object[] { p });
}
// Actually updates the progress bar:
private void UpdateProgress(float p)
{
progressBar.Value = (int)(p * (progressBar.Maximum - progressBar.Minimum)) + progressBar.Minimum;
}
}
public static class IOExtensions
{
public static long GetTotalSize(this DirectoryInfo directory, Action<float> progressCallback)
{
FileInfo[] files = directory.GetFiles("*.*", SearchOption.AllDirectories);
long sum = 0;
int countDown = 0;
for (int i = 0; i < files.Length; i++)
{
sum += files[i].Length;
countDown--;
if (progressCallback != null && countDown <= 0)
{
countDown = 100;
progressCallback((float)i / files.Length);
}
}
return sum;
}
}
It's hard to guess progress without knowing the number of files or folders first!
EDIT: I've improved the code a little.
If, when you call a method, you don't know how long the method is going to take or how many discrete steps are going to be involved, then there is no way to display a progress bar while the method is executing.
In my opinion, the purpose of a progress bar is not to give reliable information about when a task is going to be completed. Rather, the purpose is to keep the user from freaking out and cancelling the whole operation because they think your program has locked up and isn't doing anything at all.
Since you're iterating through directories and sub-directories, a simpler approach here might be to just display the current directory in a Label. This would give the user a relaxing sense that things are happening, and if the directories are all ordered alphabetically, they can even gauge for themselves the overall progress of the operation.
I would report how far you have gotten since you don't know the goal until you get there. I would do it once per invocation. Perhaps # of files and # of directories seen so far.

Categories

Resources