Apologies for long post.
I have a class (called SceneryFile) that contains a lot of elements. The user uses a 2D interface to modify the contents of this class. The results are compiled to a file that is used in a Flight Simulator Application. User actions can resultin errors where the compile will fail, or warnings where the compile will succeed but the result will not work properly in the simulator. I want to replicate to some degree programs like ReSharper or Just Code that check the state of the SceneryFile in the background while the user is working and report errors. I have tried to do this using a Background Worker but the results are not reliable.
First I created a set of arguments to pass to the background worker that contain the sceneryfile instance and some other stuff:
public class FSIssueArgs {
public FSIssueArgs(SceneryFile sceneryFile, Airport airport) {
Issues = new Dictionary<string, FSIssue>();
SceneryFile = sceneryFile;
Airport = airport;
}
public FSIssueSeverity Severity { get; set; }
public Dictionary<string, FSIssue> Issues { get; set; }
public SceneryFile SceneryFile { get; private set; }
public Airport Airport { get; private set; }
}
I am running the background worker each time it finishes. When a file is loaded I kick off the background worker and then it runs again in the completed event
private void onIssuesBackgroundWorkerRunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
var args = e.Result as FSIssueArgs;
if (args != null) {
issueStatusLevel.BackColor = args.SceneryFile.IssueStatusFlag();
G.SceneryFile.Issues = args.Issues;
}
G.IssueHandlerActive = false;
check4Issues();
}
issueStatusLevel is a button that shows a color based on errors and warnings being present. Clicking it opens a dialog that should list the issues found.
check4Issues contains the call to run the background worker
private void check4Issues() {
if (G.IssueHandlerActive) return;
G.IssueHandlerActive = true;
issuesFound = new Dictionary<string, FSIssue>();
var issueArgs = new FSIssueArgs(G.SceneryFile, G.CurrentAirport);
issuesBackgroundWorker.RunWorkerAsync(issueArgs);
}
The color of the indicator button works reliably but the list of issues does not get reported reliably. I stop the background worker running if the button is clicked and the list dialog is open.
I am sure the problem is that I do not understand how objects are passed between the main and background worker threads. I hoped that the object (SceneryFile) passed to the bakground thread is a copy and not just a reference. A method in this file is run to check for errors. The errors are stored in the file. I then send the file back as part of the args in e.Result. I now think that I am doing it wrong and somehow I should not be using the same object in two threads.
Of course, while the file is validated in the background the user is modifying it in the foreground.
So what I want ot do is send a copy of the file to the background thread that is processed but is not a reference to the file in the main thread. When it has been processed I want to send back a list of issues. I recogni开发者_C百科ze that the user may have changed the file in the meantime but I am not too concerned and the next run will catch it up.
Not clear what is scenery file object type is really from the code, but instead of coping entire object only for reason to analyze it, I would suggest to save the pointer location till which analyzer have to scan the content, file it is or just a stream. In this case you will have the same file/stream but splitted among analyzer and user.
But here youn should handle multithreading access to the same source.
EDIT
You can try to have one forward only stream reader for analyzer and stream writer for user.
Hope this helps.
Regards.
精彩评论