Try...catch mysteriously continues executing code (only sometimes...) - c#

In the C# code below, assume that sample is, say, 20000.
Then the line which calls Convert.ToInt16 will throw an overflow exception as it tries to convert 20000 * 3.2 (which is greater than 32768).
In that exception, it sets a bool flag to true (dataErrorWritten), which is supposed to stop the error message being written more than once.
However what I am seeing is some cases where the error message is continually written every time and it appears the dataErrorWritten flag is not doing anything. How can this be possible? Once the exception is caught the first time, dataErrorWritten[i] will be set to true, and when it comes around the next time it should not print any error. In fact, this works 99% of the time, however under certain strange circumstances it does not.
ProcessInData is running on its own thread within a static class.
Any ideas would be greatly appreciated. Thank you.
I have already tracked down one multi-threading bug in this program (shared data queue without lock), and I guess that this might have something to do with multi-threading but I can't see how.
private static bool[] dataErrorWritten;
private static void ProcessInData()
{
short[][] bufferedData = new short[800][];
short sample;
//initialise this bool array to false
dataErrorWriten = new bool[32];
for (int i = 0; i < 32; i++)
{
dataErrorWriten[i] = false;
}
//create buffered data arrays
for (int i = 0; i < bufferedData.Length; i++)
{
bufferedData[i] = new short[32];
}
//loop always true
while (processData)
{
//... Increment bufferLocation
for (int i = 0; i < 32; i++) {
//Get a sample of data
sample = GetSampleFromSomewhere();
try {
bufferedData[bufferLocation][i] = Convert.ToInt16(((float)sample * 3.2);
dataErrorWritten[i] = false;
}
catch (Exception) {
if (!dataErrorWritten[i]) {
EventLog.WriteToErrorLogFile("Invalid UDP sample value " + sample + " received for channel " + (i + 1).ToString() + ".");
dataErrorWritten[i] = true;
}
// ... set buffered data within bounds
}
}
}
}

Your code sets the flag to false after a successful convert and true in the handler.
If your code had a mix of good and bad converts, the flag will toggle and you get multiple errors.
You could remove the set back to "false" to ensure each error is only printed once. Perhaps use a counter instead of a bool. Only output the error when the counter is 0. That way you know how many times the error occurred (for debug purposes), but only report it once.

Related

Catch ArgumentOutOfRangeException

I have a function that is run once every second by a timer. The purpose of the function is to request data through an API and then update a list and some textboxes with the results. For the most part it runs like clockwork, but every couple of hours I get an ArgumentOutOfRangeException.
For whatever reason, either that one API request fails or the list doesn't update fast enough. Either way the function tries to update texboxes and variables using an empty list, hence the ArgumentOutOfRangeException.
Now this data is mostly not being stored for any length of time, and the function would just run again in another second anyway if not for the error popping up and stalling everything. I hadn't used C# before I made this program so I'm not sure how best to utilize the "catch" statement to just make the program ignore it and keep going. Actually it would be good if the number of failures was logged in an integer variable so that the program could determine if something was actually wrong instead of just a momentary glitch. How would you write the catch statement for this?
try
{
GetQuoteResponse resp = GetQuoteResponse.GetQuote(questradeToken, quotesSymbolIds);
List<Level1DataItem> quotes = resp.Quotes;
QuoteStream_Data.Clear();
for (int i = 0; i < quotes.Count; ++i)
{
Level1DataItem quote = quotes[i];
QuoteStream_Data.Add(new QuoteStream_Entry { lastTradePrice = Convert.ToDecimal(quote.m_lastTradePrice)});
}
XIVPriceBox.Invoke(new Action(() => XIVPriceBox.Text = QuoteStream_Data[0].lastTradePrice.ToString()));
HVIPriceBox.Invoke(new Action(() => HVIPriceBox.Text = QuoteStream_Data[1].lastTradePrice.ToString()));
TVIXPriceBox.Invoke(new Action(() => TVIXPriceBox.Text = QuoteStream_Data[2].lastTradePrice.ToString()));
XIVCurrentPrice = QuoteStream_Data[0].lastTradePrice;
TVIXCurrentPrice = QuoteStream_Data[2].lastTradePrice;
}
catch
{
}
try
{
// ...
}
catch(ArgumentOutOfRangeException ex)
{
LogException(ex);
}

Using Tasks, "Index out of Range" and IsCompleted prematurely returning true

I'm trying to test my understanding of (and learn about) tasks in "Windows Store" C#. I made a multi-tasking app that contains several progress bars and simulated tasks that count to 100 over varying periods of time. It will eventually be the basis for a mutlti-threaded file parser.
I have a task-handling task "parseFiles" that loops through a queued list of tasks until they are all complete by checking a counter.
Anyways, while this program is running, I randomly get first chance exceptions of the index out of range variety in the task handling for loop of the "parseFiles" task. The loop counter, i, somehow gets set as a value higher than possible, i.e. 3 even though the for loop clearly only sets i to a maximum of 2.
The other strange thing that happens is that the "parsing" tasks in parsers[] sometimes return a true value for IsCompleted even though they haven't started.
Any ideas on what is causing these strange bugs? Am I doing something wrong here?
I'd also gladly accept any advice on a more robust or easier way of queuing and handling the parsing tasks since it would probably fix the two bugs.
Here's the code:
namespace TaskTest
{
public sealed partial class MainPage : Page
{
testFile[] fileList;
public MainPage()
{
this.InitializeComponent();
fileList = new testFile[10];
for(int j=0; j<10; j++){
fileList[j] = new testFile();
}
}
private static void parseFile(testFile file, IProgress<int> progress)
{
progress.Report(0);
file.parse(progress);
}
public Task parseFiles(IProgress<int>[] progresses) {
int nParsers = 3;
int nParsers = 3;
if (nParsers > fileList.Length)
{
nParsers = fileList.Length;
}
Task[] parsers = new Task[nParsers];
Boolean parseCompleted = false;
Task.Run(() =>
{
//Do the parsing
int fileCounter = -1;
Boolean startedLast = false;
Boolean[] finalTasksDone = new Boolean[nParsers];
while (!parseCompleted)
{
for(int i=0; i<=(nParsers - 1); i++){
if (!startedLast && (parsers[i] == null || parsers[i].IsCompleted))
{
fileCounter++;
Debug.WriteLine("Task " + i + " completed. Starting new Task " + i + " to parse file #" + fileCounter);
if (fileCounter == fileList.Length - 1) { startedLast = true; }
Action<testFile, Progress<int>> parseAction = parseFile;
parsers[i] = Task.Factory.StartNew(() => parseFile(fileList[fileCounter], progresses[i]));
}
else
{
if (startedLast && parsers[i].IsCompleted)
{
finalTasksDone[i] = true;
}
}
}
int finishedCounter = 0;
for (int i = 0; i <= (nParsers - 1); i++)
{
if (finalTasksDone[i])
{
finishedCounter++;
}
}
if (finishedCounter >= nParsers)
{
parseCompleted = true;
}
}
});
return null;
}
public class testFile{
public async void parse(IProgress<int> progress){
Random random = new Random();
int simDelay = 1;
int simFileLength = random.Next(50, 100);
Debug.WriteLine("Starting file with length: " + simFileLength);
for(int j=0; j<simFileLength; j++){
await Task.Delay(TimeSpan.FromSeconds(simDelay));
int percentProgress = (int) (((double) j/ (double) simFileLength) * 100);
progress.Report(percentProgress);
}
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
IProgress<int>[] progresses = new Progress<int>[3];
progresses[0] = new Progress<int>(ReportProgress1);
progresses[1] = new Progress<int>(ReportProgress2);
progresses[2] = new Progress<int>(ReportProgress3);
parseFiles(progresses);
}
private void ReportProgress1(int value)
{
pBar1.Value = value;
}
private void ReportProgress2(int value)
{
pBar2.Value = value;
}
private void ReportProgress3(int value)
{
pBar3.Value = value;
}
}
}
Here's a log from a typical run.
According to this, most of the tasks don't even get started before they return true on IsCompleted.
Task 0 completed. Starting new Task 0 to parse file #0
Task 1 completed. Starting new Task 1 to parse file #1
Task 2 completed. Starting new Task 2 to parse file #2
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
Task 1 completed. Starting new Task 1 to parse file #3
Task 2 completed. Starting new Task 2 to parse file #4
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
Starting file with length: 73
Starting file with length: 83
Task 2 completed. Starting new Task 2 to parse file #5
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
Task 2 completed. Starting new Task 2 to parse file #6
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
Task 1 completed. Starting new Task 1 to parse file #7
Task 2 completed. Starting new Task 2 to parse file #8
Starting file with length: 78
Task 1 completed. Starting new Task 1 to parse file #9
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
A first chance exception of type 'System.IndexOutOfRangeException' occurred in TaskTest.exe
Additional information: Index was outside the bounds of the array.
The program '[7372] TaskTest.exe' has exited with code 1 (0x1).
The main problem I see with this code is that parseFiles() will exit prematurely in many cases. Suppose parser 0 has completed and parsers 1 and 2 still have a long way to go, when you've started all the files so startedLast is true. Now, the while (!parseCompleted) loop will execute, and within the for loop, will find parser 0 has completed and increment lastTasksCount to 1. Now, the while (!parseCompleted) loop executes again, and within the for loop, again finds that parser 0 is completed, and increments lastTasksCount to 2. This happens one more time, lastTasksCount is incremented to 3, parseCompleted is set to true, and the method exits, all while parser 1 and parser 2 are still working. I think maybe if you fix this bug, the rest of the symptoms go away - or change if another bug is exposed.
With regard to your specific symptoms, you don't say what specific symptom you think is the result of IsComplete() returning true when the task isn't started yet. There are two things that could be misleading in this respect. One is the above exiting from the parseFiles when some tasks are still in progress. The other is that the debug statement that starts with "Task X completed" will print at the beginning when parser X doesn't exist yet, just before the parser X slot is filled for the first time. The resulting debug statement could be a bit misleading.
I don't really see a way for i to go out of bounds, though if the number of files is less than the number of parsers, there will be a null pointer access. For example, if there is one file and two parsers, the first time through the for loop a parser 0 will be created for the file, startedLast will be set to true, and then the next time through the for loop the test if (startedLast && parsers[1].IsCompleted) will be executed while parsers[1] is still null. This will not cause a problem with the constants as written, however, since you have 10 files which is greater than 3, the number of parsers you have.
Again, I would fix the first bug I mentioned in the first paragraph, and possibly the bug that occurs when the number of parsers exceeds the number of files, and see if that clears up your problems.

ArgumentOutOfRangeException on SerialPort.ReadTo()

My code indeterminately throws ArgumentOutOfRangeException: Non-negative number required. when invoking the ReadTo() method of the SerialPort class:
public static void RetrieveCOMReadings(List<SuperSerialPort> ports)
{
Parallel.ForEach(ports,
port => port.Write(port.ReadCommand));
Parallel.ForEach(ports,
port =>
{
try
{
// this is the offending line.
string readto = port.ReadTo(port.TerminationCharacter);
port.ResponseData = port.DataToMatch.Match(readto).Value;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
port.ResponseData = null;
}
});
}
SuperSerialPort is an extension of the SerialPort class, primarily to hold information required for communications specific to each device on the port.
A port always has the TerminationCharacter defined;
Most of the time it's a newline character:
I don't understand why this is happening.
If the ReadTo fails to find the character(s) specified in the input buffer, shouldn't it just timeout and return nothing?
The StackTrace is pointing to an offending function in the mscorlib, in the definition of the SerialPort class:
System.ArgumentOutOfRangeException occurred
HResult=-2146233086
Message=Non-negative number required.
Parameter name: byteCount
Source=mscorlib
ParamName=byteCount
StackTrace:
at System.Text.ASCIIEncoding.GetMaxCharCount(Int32 byteCount)
InnerException:
I followed it and here's what I found:
private int ReadBufferIntoChars(char[] buffer, int offset, int count, bool countMultiByteCharsAsOne)
{
Debug.Assert(count != 0, "Count should never be zero. We will probably see bugs further down if count is 0.");
int bytesToRead = Math.Min(count, CachedBytesToRead);
// There are lots of checks to determine if this really is a single byte encoding with no
// funky fallbacks that would make it not single byte
DecoderReplacementFallback fallback = encoding.DecoderFallback as DecoderReplacementFallback;
----> THIS LINE
if (encoding.IsSingleByte && encoding.GetMaxCharCount(bytesToRead) == bytesToRead &&
fallback != null && fallback.MaxCharCount == 1)
{
// kill ASCII/ANSI encoding easily.
// read at least one and at most *count* characters
decoder.GetChars(inBuffer, readPos, bytesToRead, buffer, offset);
bytesToRead is getting assigned a negative number because CachedBytesToRead is negative. The inline comments specify that CachedBytesToRead can never be negative, yet it's clearly the case:
private int readPos = 0; // position of next byte to read in the read buffer. readPos <= readLen
private int readLen = 0; // position of first unreadable byte => CachedBytesToRead is the number of readable bytes left.
private int CachedBytesToRead {
get {
return readLen - readPos;
}
Anyone have any rational explanation for why this is happening?
I don't believe I'm doing anything illegal in terms of reading/writing/accessing the SerialPorts.
This gets thrown constantly, with no good way to reproduce it.
There's bytes available on the input buffer, here you can see the state of some of the key properties when it breaks (readLen, readPos, BytesToRead, CachedBytesToRead):
Am I doing something glaringly wrong?
EDIT: A picture showing that the same port isn't being asynchronously accessed from the loop:
This is technically possible, in general a common issue with .NET classes that are not thread-safe. The SerialPort class is not, there's no practical case where it needs to be thread-safe.
The rough diagnostic is that two separate threads are calling ReadTo() on the same SerialPort object concurrently. A standard threading race condition will occur in the code that updates the readPos variable. Both threads have copied the same data from the buffer and each increment readPos. In effect advancing readPos too far by double the amount. Kaboom when the next call occurs with readPos larger than readLen, producing a negative value for the number of available bytes in the buffer.
The simple explanation is that your List<SuperSerialPort> collection contains the same port more than once. The Parallel.ForEach() statement triggers the race. Works just fine for a while, until two threads execute the decoder.GetChars() method simultaneously and both arrive at the next statement:
readPos += bytesToRead;
Best way to test the hypothesis is to add code that ensures that the list does contain the same port more than once. Roughly:
#if DEBUG
for (int ix = 0; ix < ports.Count - 1; ++ix)
for (int jx = ix + 1; jx < ports.Count; ++jx)
if (ports[ix].PortName == ports[jx].PortName)
throw new InvalidOperationException("Port used more than once");
#endif
A second explanation is that your method is being calling by more than one thread. That can't work, your method isn't thread-safe. Short from protecting it with a lock, making sure that only one thread ever calls it is the logical fix.
It can be caused because you are setting a termination character and using this character for readto. Instead try to use ReadLine or remove the termination character.

"Use of unassigned local variable 'ponderThread'" on a previously initialized variable

I've been writing an AI that plays chess recently. The AI is designed to run two separate instances, each connected to a client server. The server calls a run function for each AI in turn. What I'm trying to do is write code that ponders while the other AI is making its move. However, I've come across an issue. I'll show the code so as to make explaining said issue easier:
public override bool run()
{
PonderSearch ponderSearch = new PonderSearch();
Thread ponderThread;
AIMove bestMove = null;
int Depth = 0;
// Print the board
if (moves.Length < 2)
{
theBoard.Print();
}
if (!FirstTurn)
{
AIMove lastMove = new AIMove(AI.moves[0]);
Depth = ponderSearch.Depth;
foreach (MoveTable result in ponderSearch.TheTable)
{
if (result.TheMove == lastMove)
{
bestMove = result.TheResult.Move;
}
}
// End thread
ponderThread.Abort();
ponderThread.Join();
}
// Looks through information about the players
for (int p = 0; p < players.Length; p++)
{
Console.Write(players[p].getPlayerName());
// if playerID is 0, you're white, if its 1, you're black
if (players[p].getId() == playerID())
{
Console.Write(" (ME)");
}
Console.WriteLine(" time remaining: " + players[p].getTime());
}
AIMove otherPMove = new AIMove();
AIPiece pieceMoved = new AIPiece();
// if there has been a move, print the most recent move
if (moves.Length > 0)
{
// Update the board state with previous move
theBoard = theBoard.Update();
pieceMoved = theBoard.GetPiece((short)moves[0].getToRank(),
(short)moves[0].getToFile());
otherPMove = new AIMove(moves[0], pieceMoved);
if (lastMoves.Count >= 8)
{
lastMoves.RemoveAt(7);
}
lastMoves.Insert(0, otherPMove);
}
// Generate move
Search theSearch = new Search(lastMoves);
if (!FirstTurn)
{
theSearch.Update(Depth, bestMove);
}
AIMove theMove = theSearch.Minimax(theBoard, (short)playerID());
// Update last 8 moves
if (lastMoves.Count >= 8)
{
lastMoves.RemoveAt(7);
}
lastMoves.Insert(0, theMove);
if (theMove != null)
{
Console.WriteLine("Move Chosen:");
theMove.Print();
theBoard = theBoard.Move(theMove, (short)playerID());
}
else
{
Console.WriteLine("No move available");
}
theBoard.Print();
// Begin pondering
ponderSearch = new PonderSearch(lastMoves, (short)playerID(), theBoard, theMove);
ponderThread = new Thread(new ThreadStart(ponderSearch.Ponder));
ponderThread.Start();
FirstTurn = false;
return true;
}
Anyway, as written, the compiler throws multiple errors saying my Thread hasn't been initialized but the point is that the function runs multiple times, ending the thread that was started in the most recent call at the beginning of the current one.
Is there any way I can do this?
Thanks,
EDIT: The error I get is:
Error 4 Use of unassigned local variable 'ponderThread' C:\Users\...\AI.CS 52 13 csclient
This has nothing to do with threading. It's a simple scoping issue. All local variables (declared inside a method) is typically put on the stack and cleaned up when the method exists.
Hence the ponderThread will be garbage collected after the run() method have exited. So the next time your method enter it will have the member variable FirstTurn set to true while ponderThread is uninitialized as it's a local variable.
A quick fix is to change the ponderThread variable to a class variable (called member variable in C#).
That will however give you thread synchronization problems as you are going to share state between two threads.
I suggest that you read up a bit more about threads before going further.

Stack overflow error in console application

I currently have a console application written in C# for production server environment. It's quite simple, but I've been testing it for +- 3 months now on my own server (semi-production, but not a disaster if the program fails). I've been getting stack overflow errors every few weeks or so, though.
Of course, pasting my entire source code here would be quite a long piece, so I will try to explain it the best I can: the program is in an infinite while loop (this is probably the cause of the issue), and it checks every second a few small things and prints to the console every so often (if no activity, every 15min, otherwise up-to every second).
Now why and how can I fix the stack overflow errors? Being able to run it for a couple weeks without issue may seem like a lot, but it is obviously not in a server production environment. My guess is that it's the fact I'm using a while loop, but what alternatives do I have?
Edit: here's a portion of the code:
int timeLoop = 0;
while (true)
{
// If it has been +-10min since last read of messages file, read again
if (timeLoop > 599)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " Reading messages...");
messagesFile = File.ReadAllText(#"messages.cfg");
messages = messagesFile.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
timeLoop = 0;
}
// For each message, check if time specified equals current time, if so say message globally.
foreach (string x in messages)
{
string[] messageThis = x.Split('~');
int typeLoop = 0;
if (messageThis[2] != "no-loop")
typeLoop = Convert.ToInt16(messageThis[2].Remove(0, 5));
DateTime checkDateTime = DateTime.ParseExact(messageThis[0], "HH:mm:ss", null);
if (typeLoop == 0)
{
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
}
else
{
DateTime originalDateTime = checkDateTime;
do
{
checkDateTime = checkDateTime.AddHours(typeLoop);
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
} while (checkDateTime.ToString("HH:mm:ss") != originalDateTime.ToString("HH:mm:ss"));
}
}
timeLoop++;
Thread.Sleep(1000);
}
Also, I forgot that I actually have this code on Github, which probably helps a lot. I know you shouldn't be using any links to code and have them here, so that's why I included the snippet above - but if you are interested in helping me out the repository is located here. Another note - I know that doing it like this is not very accurate on timing - but this is not much of an issue at the moment.
BattleEyeClient.Connect can call itself in some (failing) circumstances, and this method can be called by sayGlobal - so you probably want to change this code block (from line 98):
catch
{
if (disconnectionType == BattlEyeDisconnectionType.ConnectionLost)
{
Disconnect(BattlEyeDisconnectionType.ConnectionLost);
Connect();
return BattlEyeConnectionResult.ConnectionFailed;
}
else
{
OnConnect(loginCredentials, BattlEyeConnectionResult.ConnectionFailed);
return BattlEyeConnectionResult.ConnectionFailed;
}
}
Maybe keep track of how many reconnection attempts you make or transform this section of code so that it is a while loop rather than a recursive call during this failure mode.
Even worse, of course, is if that recursive Connect call succeeds, this catch block then returns BattlEyeConnectionResult.ConnectionFailed which it probably shouldn't.

Categories

Resources