Trouble Executing Tasks in C# - c#

Forgive me if the problem seems obvious. I'm new to programming, started last July. I built a really cool project that prints dozens of Report Types based on a series of Templates. This particular problem happened after I cleaned up some dirty code. I didn't think any changes had been made to these lines.
This line of code worked perfectly before the changes. Now, it seemingly doesn't even open a new process to DoWork().
//For Reference: this is in Main()
var PrintingTask = new Task(csvStatements.PrintStatementPDF);
PrinterThreads.Add(PrintingTask);
Parallel.ForEach(PrinterThreads, t =>
{
t.Start();
});
Task.WaitAll(PrinterThreads.ToArray());
I commented that out, and just ran the job as a method call from csvStatements. So I wrote csvStatements.PrintStatementPDF();
In my code, I print statements to a colored template, but I also print them as just text on a white page (so we can use the last of our special papers we used before, which has the template on them).
That task is written like so:
//For Reference: this is in my csvStatements object from above.
using (StreamReader sr = new StreamReader(csvFile))
{
//2d Array. Left dimension is the page number, Right dimension is the text field number.
var Fields = new System.Collections.Generic.List<List<string>>();
while (!sr.EndOfStream)
{
var Field = sr.ReadLine().Split('\t').ToList();
Fields.Add(Field);
}
var BlankVersion = new PrintBlankStatement();
using (var PrintingTask = new Task(() => BlankVersion.PrintBlankStatementPDF(Fields)))
{
PrintingTask.Start();
//I just added the line below. It wasn't originally there.
await Task.WhenAll(PrintingTask);
}
}
And, while that tasks runs, the program continues to print the statements to the template. So they should run in parallel. But now, when stepping through the project, the first block of code seemingly executes instantaneously (which is absurd, given the 300 pages of pdfs it needs to do) and doesn't actually produce the pdfs. The second block of code somehow also exits the program with code 0 (even though that's something done in Main(), which it shouldn't be able to do).
Did I make some change to these tasks that rendered them useless or is it more likely that the error is elsewhere in my project?

Related

Process output redirection on a single console line

I am writing a C# application that can launch third party command line executables and redirect their standard output to a RichTextBox.
I am able to redirect the output alright by using the process.OutputDataReceived event. I have a queue that I push lines to, and then I use a timer to periodically dump all the queued lines into the RichTextBox.
This works perfectly for some third party programs.
The problem lies with programs that write to a single line of the console multiple times. eg: 5% -> 10% -> 25% etc... (constantly rewriting the same spot)
This is done, I suppose, by not putting a line feed character, but rather simply returning to the beginning of the line with a carriage return and writing over the previous characters.
What happens is that the OutputDataReceived does not seem to have any way of indicating if a new line should be applied or not so my RichTextBox output simply has multiple updates on new lines.
eg:
5%
10%
25%
etc...
Is there any way to tell if the standard output is going on a new line or the same line?
If I understand correctly, you are currently seeing progress updates reported to your RichTextBox control as individual lines, while you would like to emulate the behavior of the console window. I.e. to overwrite the previously output line with the new one, rather than keeping the previous line and adding a new one. With that in mind…
The .NET types, including things like TextReader and the Process class's handling of output, consider a newline to be any of \r, \n, or \r\n. So even a process that is simply using a \r to overwrite the current line would still be interpreted by OutputDataReceived as starting a new line. Given how consistent this behavior is across .NET, your only real option is to avoid using any built-in line-based I/O mechanisms.
Fortunately, you can get asynchronous reads from the process directly via StandardOutput, instead of having to handle the line-based OutputDataReceived event. For example:
async Task ConsumeOutput(TextReader reader, Action<string> callback)
{
char[] buffer = new char[256];
int cch;
while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
callback(new string(buffer, 0, cch));
}
}
You might call it like this:
// don't "await", but do keep "task" so that at some later time, you can
// check the result, "await" it, whatever, to determine the outcome.
Task task = ConsumeOutput(process.StandardOutput, s =>
{
richTextBox1.AppendText(s);
});
Of course, without any modification the above will just do what you are already getting. But reading the output this way will not do any interpretation of the line-break characters. Instead, they will be present in the string s that is passed to the anonymous method handling each read callback. So you can scan that string yourself, looking for lone carriage returns that indicate that you are starting a new line, but should delete the previous line before adding the new text. Be sure to add (or at least skip) all of the text up to the carriage return first, and then delete the last line, before adding the new text.
This code will fix up raw output and make it as it would appear on the terminal.
//Deletes all lines that end with only a CR - this emulates the output as it would be seen cmd
public static string DeleteCRLines( this string Str) {
Str = Str.Replace( "\r\r\n", "\r\n");
//Splits at the CRLF. We will end up with 'lines' that are full of CR - the last CR-seperated-line is the one we keep
var AllLines = new List<string>( Str.Split( new[] {"\r\n"}, StringSplitOptions.None));
for (int i = 0; i < AllLines.Count; i++){
var CRLines = AllLines[i].Split('\r');
AllLines[i] = CRLines[ CRLines.Count() -1];
}
return String.Join( Environment.NewLine, AllLines.ToArray());
}

Ensure data deserialization / serialization

I have 3 ObservableCollections in my ViewModel and one Class which I load when you run an app.
To ensure ObservableCollections are deserialized I just got.
if(SomeCollection.Count == 0)
ThisCollection = await deserializationMethod<ObservableColletion<T>>(filename);
If there is no file, deserializationMethod will create new object with
return Activator.CreateInstance<T>();
That works fine - no problem with that.
And for class I have
if(ClassObject.Loaded != true)
ThisObject = await deserializationMethod<T>(filename);
I added a property - if file is deserialized then it's true.
It looks like it works but it is NOT. It happens very rarely but sometimes file is not deserialized and when you use an app this file is overwritten so every data are destroyed. I cannot find what is causing the problem. It is that you just run an app and it happens - like once per 100 runs.
How to be very sure that if file exist then it will be deserialized for sure?
Or maybe I should make List of these ObservableCollections + Class and serialize it to one file? Is there any good practice with that?
EDIT:
I used SemaphoreSlim to ensure that everything is used as it supposed to, but today it happened again.
The thing is it happens when app is started and nothing else is even tapped. There is no way that something is writing at this moment. It looks like data is not deserialized or is not reading the file that exist. Because every changes are written with closing an app then everything is gone.
Any other ideas what it might be or how to be sure that data are deserialized?
EDIT FINAL - reproduced problem:
I finally reproduced what is going on. So I've removed edits with code that wasn't necessary here.
I have BackPressed event to handle when user is going back or want to exit an app (if on MainPage).
This part of code apparently was causing the problem. What is going on exactly.
First thing is that problem isn't possible to be reproduced using emulator.
My BackPressed method contained await with serializing method that saved the data that were later gone (so as Ondrej Svejdar has written it was writing before reading). BUT I started to test it and there is strange behaviour and I still have some questions about it.
How it happens.
When I started an app (by accident e.g.) and loading screen occurs I start to tap back button few times -> app isn't running it is closing ASAP and I can't even see a UI (sometimes I am able to see AppBar for a moment). Then when I try to open app again (doesn't matter if immediately or later) it is "resuming" and after this exact moment my data are gone. But not all of the data. Only the last one saved with await within BackPressed method. Only this one. I tried to save One, Two and Three ObservableCollections with and without this Class and ALWAYS the last one was saved "empty". After this awaits I got Application.Current.Exit() method that might cause this, but I'm not sure if this should matter when serializing method is Task and only the last one is wrongly serialized.
When I remove this awaits from BackPressed method I can't reproduce this issue so this is it.
Questions I still have are: Is this behavior expected? Is there better method to close an app and ensure serializing data or I just should save it during using an app not while exiting it?
If someone is interested how to do it properly I was thinking about it and come up with few conclusions.
Keep in mind that this are my suggestions and there might be better approach.
While handling BackPressedButton event (the hardware one) I had an implementation of GoBack to previous page (if not on MainPage) or leave an app if on MainPage.
I was closing an app using Application.Current.Exit() and that wasn't causing problems (because I was saving very small files) until I started doing strange things (read "EDIT FINAL - reproduced problem:" of the question for more details).
Thing was the file wasn't saved because an app was closed before writing has finished. Solution is actually very simple. To my Save method which is a Task it just should return true value when writing is finished and this value should be checked while closing an app.
bool saved = await saveDataAsync<T>(whichData, dataFileName)
if(saved)
Application.Current.Exit();
and serializing method looks like this (I'm using semaphoreSlim in case there is possibility to two methods trying to reach the same file)
public async Task<bool> saveDataAsync<T>(T whichData, string dataFileName)
{
var Serializer = new DataContractSerializer(typeof(T));
await mySemaphoreSlim.WaitAsync();
try
{
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(dataFileName, CreationCollisionOption.ReplaceExisting))
{
Serializer.WriteObject(stream, whichData);
}
}
finally
{
mySemaphoreSlim.Release();
}
return true;
}

CPU is 100% at multithreading

First I've read all the posts here regarding this issue and I manged to progress a bit. However it seems I do need your help :)
I have a program with several threads, sometimes (not always) the CPU usage of the program is increasing up to 100% and never reduced until I shut down the program.
As I read in other similar posts, I ran the app using the visual studio (2012 - Ultimate).
I paused the app, and open the threads window.
There I pauses the threads until I've found the 4 threads which stuck the app.
The all refer to the same line of code (a call for constructor).
I checked the constructor inside and outside and couldn't find any loop which could cause it.
To be more careful I've added break point to almost every line of code and resume the app. None of them have been triggered.
This is the line of code:
public static void GenerateDefacementSensors(ICrawlerManager cm)
{
m_SensorsMap = new Dictionary<DefacementSensorType, DefacementSensor>();
// Create instance of all sensors
// For any new defacement sensor, don't forget to add an appropriate line here
// m_SensorsMap.add(DefacementSensorType.[Type], new [Type]Sensor())
try
{
if (m_SensorsMap.Count <= 0)
{
m_SensorsMap.Add(DefacementSensorType.BackgroundSensor, new BackgroundSensor());
m_SensorsMap.Add(DefacementSensorType.TaglinesSensor, new TaglinesSensor(cm.Database));
m_SensorsMap.Add(DefacementSensorType.SingleImageSensor, new SingleImageSensor());
}
}
catch (Exception)
{
Console.WriteLine("There was a problem initializing defacement sensors");
}
}
The second "m_SensorsMap.Add" is marked with green arrow, as I understand it, it means it's still waiting to the first line to finish.
By the way, the m_SensorsMap.Count value is 3.
How can I find the problem?
Is it a loop?
Or maybe a deadlock (not make sense because it shouldn't be 100% cpu, right?)
It's pointless to upload a code because this is a huge project.
I need more general help like how to debug?
Is it could something else than a loop?
Because it's a bug that returns every while and than I'm not closing the app until I found the problem :)
Thanks in advance!!
Edit:
The constructors:
public TaglinesSensor(IDatabase db)
{
m_DB = db;
}
I couldn't found the problem so I've changed the design on order not to call those constructors anymore.
Thanks for the guys who tried to help.
Shaul

Xamarin.Mac NSThread.Start() stack overflow

I've got a rather complex Xamarin.Mac application. In fact, it's a windows forms application, but we're using Mono for Mac compatibility with a native Mac GUI. One of our business logic components involves watching the filesystem for changes using FSWatcher. Unfortunately, FSWatcher on Mac is horribly broken, leaving us to use the native FSEvents API via Xamarin.Mac.
Deep down in business logic, I've got a custom class called CBFileSystemWatcher which wraps the .NET FSWatcher, and on mac provides an adapter between the FSWatcher-expecting business logic and FSEvents on mac. INSIDE this compatibility class, I've got
private FSEventStream eventStream;
//...
this.eventStream.ScheduleWithRunLoop (NSRunLoop.Main);
which schedules the filesystem events on the main run loop. Unfortunately, this means the GUI blocks FS event handling, so suddenly if a modal dialog is open, for example, fs events stop getting processed.
My thought is to create a new runloop for the FS event scheduling, which I figure looks like
NSThread.Start(()=>{
// Some other code
this.eventStream.ScheduleWithRunLoop (NSRunLoop.Current);
});
The snag is, I think, that this code runs inside maybe two other layers of thread starts. For testing purposes, I've got the following code where I NEED the above code:
NSThread.Start(()=>{
int i = 0;
});
with a breakpoint on the middle line to determine whether it was hit. 9 times out of ten I get the following stack overflow:
Stack overflow in unmanaged: IP: 0x261ba35, fault addr: 0xb02174d0
Stack overflow in unmanaged: IP: 0x261ba35, fault addr: 0xb02174d0
(the addresses change, though often recur)
One time out of ten the code works exactly as expected and I break on i=0
To test this further, I placed the above test inside my main AppDelegate.cs FinishedLaunching method. There, the code reliably works.
To further confuse matters, I placed the following code at the start of FinishedLaunching:
var fooThread = new Thread(() =>
{
var barThread = new Thread(()=>{
NSThread.Start(() =>
{
int i = 4;
});
});
barThread.Start();
});
fooThread.Start();
With breakpoints on fooThread.Start();, barThread.Start();, and int i = 4; the code works exactly as expected, where the points are hit in reverse order.
My question is, does anyone have any ideas on how to even begin deubgging this? The SO is so out of the blue I don't even know where to start.
A year later, I have this answer for you:
http://forums.xamarin.com/discussion/37451/more-modal-problems-nsmenu-nsstatusitem

Force loop containing asynchronous task to maintain sequence

Something tells me this might be a stupid question and I have in fact approached my problem from the wrong direction, but here goes.
I have some code that loops through all the documents in a folder - The alphabetical order of these documents in each folder is important, this importance is also reflected in the order the documents are printed. Here is a simplified version:
var wordApp = new Microsoft.Office.Interop.Word.Application();
foreach (var file in Directory.EnumerateFiles(folder))
{
fileCounter++;
// Print file, referencing a previously instantiated word application object
wordApp.Documents.Open(...)
wordApp.PrintOut(...)
wordApp.ActiveDocument.Close(...)
}
It seems (and I could be wrong) that the PrintOut code is asynchronous, and the application sometimes gets into a situation where the documents get printed out of order. This is confirmed because if I step through, or place a long enough Sleep() call, the order of all the files is correct.
How should I prevent the next print task from starting before the previous one has finished?
I initially thought that I could use a lock(someObject){} until I remembered that they are only useful for preventing multiple threads accessing the same code block. This is all on the same thread.
There are some events I can wire into on the Microsoft.Office.Interop.Word.Application object: DocumentOpen, DocumentBeforeClose and DocumentBeforePrint
I have just thought that this might actually be a problem with the print queue not being able to accurately distinguish lots of documents that are added within the same second. This can't be the problem, can it?
As a side note, this loop is within the code called from the DoWork event of a BackgroundWorker object. I'm using this to prevent UI blocking and to feedback the progress of the process.
Your event-handling approach seems like a good one. Instead of using a loop, you could add a handler to the DocumentBeforeClose event, in which you would get the next file to print, send it to Word, and continue. Something like this:
List<...> m_files = Directory.EnumerateFiles(folder);
wordApp.DocumentBeforeClose += ProcessNextDocument;
...
void ProcessNextDocument(...)
{
File file = null;
lock(m_files)
{
if (m_files.Count > 0)
{
file = m_files[m_files.Count - 1];
m_files.RemoveAt(m_files.Count - 1);
}
else
{
// Done!
}
}
if (file != null)
{
PrintDocument(file);
}
}
void PrintDocument(File file)
{
wordApp.Document.Open(...);
wordApp.Document.PrintOut(...);
wordApp.ActiveDocument.Close(...);
}
The first parameter of Application.PrintOut specifies whether the printing should take place in the background or not. By setting it to false it will work synchronously.

Categories

Resources