I use a RaspberryPi with Mono to run an application. It reads input from stdin and prints output to stdout. Every line in stdin is a record and every line in stdout is a records. Input records may be dropped.
I use two threads: First i used a Producer/Consumer pattern. The producer just took the stdin lines and put them to a queue. The consumer always checked the queue and handled the items.
I used the Monitor-class to implement this, and semaphores and also an AutoResetEvent. I always got this error after a some time:
Unhandled Exception:
System.InvalidOperationException: The event is already set
at System.Threading.CountdownEvent.Signal (Int32 signalCount) [0x00000] in <filename unknown>:0
at System.Threading.CountdownEvent.Signal () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.CountdownContinuation.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ProcessCompleteDelegates () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Finish () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ThreadStart () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.TpScheduler.<QueueTask>m__0 (System.Object l) [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: The event is already set
at System.Threading.CountdownEvent.Signal (Int32 signalCount) [0x00000] in <filename unknown>:0
at System.Threading.CountdownEvent.Signal () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.CountdownContinuation.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ProcessCompleteDelegates () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Finish () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.ThreadStart () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.Task.Execute () [0x00000] in <filename unknown>:0
at System.Threading.Tasks.TpScheduler.<QueueTask>m__0 (System.Object l) [0x00000] in <filename unknown>:0
at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
Currently i use a "stupid" approach. I use the reader from here: How to add a Timeout to Console.ReadLine()?
I use an endless loop which always gets the available lines from stdin and takes tha last one and gives it to the worker. The worker needs much time for the work and then everything restart.
Code:
using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Collections.Generic;
using System.Threading;
using SourceAFIS.Simple;
using NetJSON;
namespace fingerprint_to_iso
{
class Program
{
private static AfisEngine afis;
private static Queue<Tuple<DateTime, string>> inputFiles;
private static volatile bool stop;
private static AutoResetEvent queueEvent;
private static void printJson(Tuple<DateTime, string> fingerprintImage)
{
... /* This takes about ~2s */
Console.WriteLine(json);
}
/* https://stackoverflow.com/questions/57615/how-to-add-a-timeout-to-console-readline */
class Reader
{
private static Thread inputThread;
private static AutoResetEvent getInput, gotInput;
private static string input;
static Reader()
{
getInput = new AutoResetEvent(false);
gotInput = new AutoResetEvent(false);
inputThread = new Thread(reader);
inputThread.IsBackground = true;
inputThread.Start();
}
private static void reader()
{
while (true)
{
getInput.WaitOne();
input = Console.ReadLine();
gotInput.Set();
}
}
public static string ReadLine(int timeOutMillisecs, ref bool eof)
{
getInput.Set();
bool success = gotInput.WaitOne(timeOutMillisecs);
if (success)
{
if (input == null)
{
eof = true;
}
return input;
}
else
{
eof = false;
return null;
}
}
}
static void Main(string[] args)
{
afis = new AfisEngine();
Reader reader = new Reader();
while (true)
{
string line = null;
string tmp = null;
bool eof = false;
int timeout = 100;
while ((tmp = Reader.ReadLine(timeout, ref eof)) != null && !eof)
{
if (line != null && File.Exists(line))
{
File.Delete(line);
Console.WriteLine(line + " dropped");
}
line = tmp;
timeout = 5; // Decrease timeout
}
if (line != null)
{
printJson(new Tuple<DateTime, string>(DateTime.Now, line));
}
if (eof)
{
break;
}
}
}
}
}
So, the only place where threads are used is the Reader-class. I cannot see why i always get this threading error? Sometimes i get it after a few seconds, sometimes after a few minutes.
Maybe someone has an idea?
Thank you very much
-edit-
Today i continued testing. Unfortunately i did not get the error till now. I still created a more minimal version of the code and i am very interesting to fix this bug. I let it run now until i get the error. When the error appears i will post the minimal code and also more details about the mono-version.
-edit-
The test runs now for hours, but nothing happens. It really seems that SourceAFIS (https://sourceafis.angeloflogic.com/) makes the problems. Thanks for the help:)