-1

I ran into problem while executing windows service in C#, not sure but probably due to the deadlock between the thread listening to the event handler and the normal code flow. The service just hangs when an event is listened and back to the normal flow where the Thread.Sleep is executed. The windows service goes into sleep mode normally in the first time, and in the next time the duration gets automatically doubled and thereafter it never wakes up and the service moves into a "Deadlock" mode.

There is one global variable in the below snippet controller.DeviceState, which is used both by the event listener and the main flow. All the exceptions are handled. Please let me know why the code just goes into "never waking sleep mode"

Below is the general code flow:

Main service

public partial class MainService : ServiceBase
{

    protected override void OnStart(string[] args)
    {
        try
        {

            ThreadStart start = new ThreadStart(MainProcess); 

            Thread mainProcessThread = new Thread(start);

            // set flag to indicate worker thread is active
            serviceStarted = true;

            // start threads
            mainProcessThread.Start();
        }
        catch(Exception ex)
        {
            //catch exception
        }
    }

    string testVariable = "YES";


    //Event handler
    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        System.IO.Ports.SerialPort sp = (System.IO.Ports.SerialPort)sender;
        string s = sp.ReadExisting();

        if (s == "Wifi")
        {
            testVariable = "NO";
        }
    }

    private void MainProcess()
    {

        try
        {
            int i = 0;

            System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4");

            sp.Open();
            sp.DataReceived += serialPort1_DataReceived;

            sp.BaudRate = 9600;
            sp.DataBits = 8;
            sp.Parity = System.IO.Ports.Parity.None;
            sp.StopBits = System.IO.Ports.StopBits.One;
            sp.Handshake = System.IO.Ports.Handshake.None;
            sp.DtrEnable = true;

            while (testVariable == "YES")
            {

                i++;
                //Sleep until the testVariable is set to NO
                Thread.Sleep(5000);
            }


        }
        catch(Exception ex)
        {
            //catch exception here
        }
    }

    protected override void OnStop()
    {

    }
}
Dhiraj Dhakal
  • 238
  • 1
  • 8
  • does it run okay in a console application or a unit test? Usually when I write services I have at least three projects. The business logic, service runner and a console runner. This way I can do all my debugging in the console runner before deploying a service. I also have an interface for logging with a console logger and a windows event viewer logger. the logging can help troubleshoot when running in a service where the debugger can't attach. at a glance, everything looks okay. it shouldn't make a difference, but is it the same with a System.Timers.Timer instead of a new thread? – Joe_DM Jul 15 '17 at 04:15
  • p.s. I know it's not related by i prefer timers for services, because a Thread.Sleep will block a thread while the Timer get's callbacks from the OS and is designed for this type of work, so less CPU cycles wasted and more event driven triggers :) Conceptually I think they should both work okay though, so this comment is very unrelated to the question. – Joe_DM Jul 15 '17 at 04:17
  • You need to post at least enough of the code to show why you expect it to do anything. At present, we don't even know what inherited class the OnDataReceived method relates to. – Harry Johnston Jul 15 '17 at 04:29
  • @Joe_DM : I had used using System.Timers.Timer thread but later I got to know that, doing this it would creates its own threads and would conflicts with Thread.Sleep resulting again in the hanging mode. @ Harry Jonhnston: The datareceived uses SerialDataReceivedEventHandler i.e. the class to receive the data from the serial port. – Dhiraj Dhakal Jul 15 '17 at 04:46
  • Does `OnDataReceived` actually ever receive a "00"? Have you considered the possibility that it is receiving each character individually, i.e., two consecutive calls with "0" rather than one call with "00"? – Harry Johnston Jul 15 '17 at 06:36
  • @HarryJohnston Yes indeed, the function receives "00" at one call only. – Dhiraj Dhakal Jul 15 '17 at 06:48
  • D'oh! It's a typo. The loop says `controller.DeviceState = DeviceState.Inprogress` instead of `controller.DeviceState == DeviceState.Inprogress`. – Harry Johnston Jul 15 '17 at 07:09
  • @HarryJohnston : This is just a demo code, I have only extracted the necessary steps out of it. So that does not matter here. – Dhiraj Dhakal Jul 15 '17 at 10:15
  • We can't help you if you post fake code. Please provide a [mcve]. – Harry Johnston Jul 15 '17 at 10:17
  • @HarryJohnston:I have now added the running code, when a log is put inside the while loop of the MainProcess, the log is written 1 time & after that the serialport event handler continuosuly retrieves the data from the port.But as soon as the data stops being retrieved,the code doesn't return to main process, instead the whole service go to hang mode. I'd rather expect the main flow would still run inside while loop when the data from the serial port are being stopped retreiving. So can you tell me how can i make both things run simultaneously with no intervention or going into the HANG mode. – Dhiraj Dhakal Jul 16 '17 at 01:55
  • It looks to me as if the code as currently posted will idle - which might look like a hang, depending on what exactly you mean by the term - as soon as `testVariable` is changed; MainProcess() will exit, causing the SerialPort object to be deleted, at which point (as far as I can see) the code does exactly nothing until such time as the service is restarted. What were you expecting to happen? – Harry Johnston Jul 16 '17 at 06:47
  • Incidentally, I think you need to set the properties of the SerialPort object - the baud rate, etc. - *before* calling Open(). At least, that's how [the example code](https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open(v=vs.110).aspx) does it. – Harry Johnston Jul 16 '17 at 06:50
  • @HarryJohnston: I was expecting to run the process inside the while loop in MainProcess() even though the handler is in idle mode. In the above example, the data "Wifi" is never retrieved, so regardless of event fired the main thread which is MainProcess() should have to be run always isn't it? But that is what not happening. – Dhiraj Dhakal Jul 16 '17 at 09:02
  • How can you tell? From the log? Please include the logging code. – Harry Johnston Jul 16 '17 at 21:55
  • You might need a [`volatile` qualifier on `testVariable`](https://thedailywtf.com/articles/nature-in-its-volatility). – Harry Johnston Aug 04 '17 at 02:28

1 Answers1

0

I think now i actually figured out what was causing the deadlock. In order to replicate, I increased the sleep time to 20 seconds and ran. What i found is, when a message is retrieved from the event handler during that period(sleep time) then the whole application goes to the hang mode, I don't understand the actual reason, but IMO the Thread.Sleep would also prevent any event handlers to listen and if it does then whole system would go to the "DEAD" mode.

To fix it, I initialized in the MainClass,

private static AutoResetEvent event_1 = new AutoResetEvent(true);

And added event_1.Set(); prior to Thread.Sleep as below:

while (testVariable == "YES")
{
     Common.WriteLogIntoFile("i", i.ToString(), "FaxWorker()");
     i++;
     event_1.Set();
     Thread.Sleep(20000);
 }

But I don't know how it fixes it, if anyone knows it please let me know.

Dhiraj Dhakal
  • 238
  • 1
  • 8
  • Have you checked this topic? https://stackoverflow.com/questions/466474/how-do-i-use-datareceived-event-of-the-serialport-port-object-in-c – vasek Jul 17 '17 at 05:10
  • @vasek: There is nothing related with my issue, the data are being received, not a problem. The problem here is the windows service goes into never waking mode once the thread.sleep was fired and at the same time the serial port sends the message to the OndataReceived Event listener, due to which the sent message is never received. – Dhiraj Dhakal Jul 17 '17 at 05:33
  • try to copy your code into console app and see if that helps. It might be service related. If it doesn't help and your app is still broken, post here full minimal reproducible code. It should be easily reproduced since your terminating string is never received. – vasek Jul 17 '17 at 05:47
  • @vasek: The code in my first post is the workable one. I am working with the same. – Dhiraj Dhakal Jul 17 '17 at 05:51
  • Yes indeed, in console app we don't need any thread to start the process as windows service, hence these things won't happen there and also in windows form app. – Dhiraj Dhakal Jul 17 '17 at 06:00
  • If your code works in other application types, your problem will be elsewhere. You might want to rewrite your received data logic and not using the data received event at all, see this: https://stackoverflow.com/questions/4345331/c-sharp-serialport-datareceived-problem-when-when-attached-strings. Nevertheless, your code works *exactly as-is* for me (tested in service app, event gets fired repeatedly) – vasek Jul 17 '17 at 06:36
  • No this is not my problem either, i am receiving the message correctly however after some point the whole system hangs and neither the messages are retrieved nor the main flow continues, which I expect to. And as far as I know we cannot capture the exception either as each data received is spawned with the new thread, if i am right. Please let me know. – Dhiraj Dhakal Jul 17 '17 at 13:56
  • No, you won't get two overlapping `DataReceived` events. However you must *not* rely on the fact the data read by `sp.ReadExisting()` is complete! See this: http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport – vasek Jul 17 '17 at 14:02