I have very complicated mission. I have 2 project that contacts one of each other with TCP connection (listener and client). I want to check in the server program if I got message from the client in the last 5 seconds. The client program send message every 3 seconds automatically if he is connected to the server(The connect function by clicking on "Connect to server" button).
The advanced here is that I need the Server to do other things too so it must to be in thread.
I had an idea that the server contains thread that start when the client send the FIRST message. When the thread start it start the timer every 5 seconds it check a variable that increase every 5 seconds OR every get message(And when I get message I stop the timer and start him from the beginning again).
I tried to do it but without success. I will add my code but it doesn't work. If anyone have an idea I would be very happy I tried for hours to do it.
Code :
//Definition
private int radarPulseNumber;
private int counterTimer; // It the counter of the timer tick's
private bool ifItFirstPulse = true;
private System.Timers.Timer timerForPulse;
private Thread TimerCountRadarPulse;
// Start the thread
TimerCountRadarPulse = new Thread(() => { ifHaveConnection(); });
TimerCountRadarPulse.Start();
private void DrawForPulseMessage(object ls)
{
Dispatcher.Invoke(new Action(() =>
{
if (ifItFirstPulse)
{
ifItFirstPulse = false;
// Create a timer with a 5 second interval.
timerForPulse = new System.Timers.Timer(5000);
// Hook up the Elapsed event for the timer.
timerForPulse.Elapsed += OnTimedEvent;
timerForPulse.Enabled = true;
}
else
{
counterTimer++;
timerForPulse.Stop();
timerForPulse.Start();
}
radarPulseNumber++; // It is the counter how much recieve message we got from the client
lbl_Pulse.Content = "" + radarPulseNumber.ToString();
ImageConnect.Visibility = Visibility.Visible;
ImageDisconnect.Visibility = Visibility.Collapsed;
}));
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
counterTimer++;
}
private void ifHaveConnection() // Actually it's the function that checks the tick's of timer vs the actually recieves.
{
if (l.numOfPulseRecieves != radarPulseNumber) // l.numOfPulseRecives is an field in object who gets the number of recieve from client
{
Dispatcher.Invoke(new Action(() =>
{
// Initiallized variables for reConnect to server.
radarPulseNumber = 0;
counterTimer = 0;
ImageConnect.Visibility = Visibility.Collapsed;
ImageDisconnect.Visibility = Visibility.Visible;
}));
}
}
Related
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()
{
}
}
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.
i am trying to use a third party telnet library "active expert" for a basic telnet session.
in my UI code behind i have something like
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ts = new TelnetService();
await ts.DoConnect(node);
}
and my TelnetService looks like this
public class TelnetService
{
private Tcp objSocket = new Tcp();
private NwConstants objConstants = new NwConstants();
public string Responses { get; set; }
private Timer timer1 = new Timer();
public TelnetService()
{
timer1.Elapsed += timer1_Elapsed;
timer1.Interval = 100;
timer1.Start();
}
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
public Task DoConnect(Node node)
{
return Task.Factory.StartNew(() =>
{
objSocket.Protocol = objConstants.nwSOCKET_PROTOCOL_TELNET;
objSocket.Connect(node.IP, 23);
while (true)
{
if ((Responses == null) || (!Responses.Contains(node.WaitString))) continue;
//do something
Responses = "";
break;
}
});
}
}
there are two important pieces of functionalities.
First in the timer1_Elapsed function which is process that will keeps on ruining and checks if there is data on socket, and if there is, it will append it to a string "Response". and i am using "timer" for it.
Second in the DoConnect function which will check the"Response" string for a certain input. for this i am using async await and Task.
in a nutshell first one accumulating the Response and Second one checking the Response.
Problem is that it looks like the timer code in general and
objSocket.ReceiveString()
line specifically is causing the UI thread to halt for several seconds. which means after clicking the button i cannot move my main form on the screen however the code is running in a separate thread.
i have tried using pure Thread for this but it didn't helped either.
update
instead of timer i am using a method AccumulateResponse
public static void AccumulateResponse()
{
while (true)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
}
and calling it like
var t = new Task(TelnetService.AccumulateResponse);
t.Start();
await TelnetService.DoConnect(node);
still no luck
The DoConnect isn't your problem. It is your Timer Elapsed Event handler.
The timer elapsed event is NOT asynchronous. Only the DoConnect is.
If there is no asynchronous version of ReceiveString() from your third party lib, then use Task.Run there as well inside of an async timer1_elapsed method.
I have a WinForms application that consists of a main UI thread and 4 tasks. My main form has a private member level variable like this:
private bool keepThreadsRunning = false;
In the Load() event of my main form, I have the following:
keepThreadsRunning = true;
var task1Worker = Task.Factory.StartNew(() => DoStuff1());
var task2Worker = Task.Factory.StartNew(() => DoStuff2());
var task3Worker = Task.Factory.StartNew(() => DoStuff3());
var task4Worker = Task.Factory.StartNew(() => DoStuff4());
Inside of each of my DoStuff() methods, I basically have this:
while (keepThreadsRunning)
{
// do work here
Thread.Sleep(30000); // a couple of my tasks only need to run every 30 seconds or so
}
Lastly, in my Form_Closing() event handler, I have the following:
keepThreadsRunning = false;
this.Close();
Watching my application in task manager, it appears that the process is ending when I close my form but I'm a little confused about the four tasks. Is my call to this.Close() really causing those tasks to terminate (even if they're in the Thread.Sleep() call when it happens)? And is there a better way of accomplishing this than the way I'm coding it right now?
EDIT - I've looked briefly at task cancellation (when my app exits) but my understanding is that my tasks would need to periodically check the cancellation token to determine if they've been cancelled. Given that some of my tasks need to run every 30 seconds, I couldn't figure out how I'd implement that 30s wait (currently a Thread.Sleep()) and still have the task be checking the cancellation token.
Rather than using a boolean and Thread.Sleep(), use a WaitHandle, specifically a ManualResetEvent, created like this:
var threadTerminationHandle = new ManualResetEvent(false);
In your thread:
do {
// do work here
} while (!threadTerminationHandle.WaitOne(TimeSpan.FromSeconds(30))
This will wait until the WaitHandle is set, or 30 seconds elapses, whichever is sooner.
In your form:
threadTerminationHandle.Set();
Close();
First of all, closing the main UI thread will terminate your other tasks. If you need them to keep running, maybe consider running them in a seperate Console Application, or a Windows Service.
Even if you found a way to delay the closing of the form while you finish running the methods you need to run, this would only work if the end user closed the form in the way you wanted, and Windows being Windows there are a million and one ways to close an application so there is no guarantee that this will work.
For running a method asynchronously every x amount of seconds, you could just use a timer for the whole thing, like so:
using System;
using System.Timers;
using System.Windows.Forms;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var timer1 = new System.Timers.Timer { Interval = 30000, Enabled = true };
var timer2 = new System.Timers.Timer { Interval = 20000, Enabled = true };
var timer3 = new System.Timers.Timer { Interval = 10000, Enabled = true };
var timer4 = new System.Timers.Timer { Interval = 5000, Enabled = true };
timer1.Elapsed += timer1_Elapsed;
timer2.Elapsed += timer2_Elapsed;
timer3.Elapsed += timer3_Elapsed;
timer4.Elapsed += timer4_Elapsed;
}
void timer4_Elapsed(object sender, ElapsedEventArgs e)
{
//do work here
}
void timer3_Elapsed(object sender, ElapsedEventArgs e)
{
//do work here
}
void timer2_Elapsed(object sender, ElapsedEventArgs e)
{
//do work here
}
void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
//do work here
}
}
}
When you close application, tasks will be closed accordingly because task is processed under background thread from thread pool. So, you don't need to periodically check the cancellation token to determine if they've been cancelled
I have a sub which starts one of two timers (depending on 'zone' condition). This sub called 'CheckAndActivateRelays' is itself called by a Serial Port _DataReceived event. I am inserting break points to help me troubleshoot and am seeing that the tmrSoundSirensAfterDelay.Start() line is being executed successfully with the status of the timer even changing to enabled. However the associated Tick event never executes any of the code contained within it.
If I do the same thing by calling the sub from within button24's click event, it works perfectly. Everything is on the same Form with no threaded processes.
Anyone? Thanks
private void checkAndActivateRelays(int zoneNumber)
{
if (globalFullAlarmSet || globalNightAlarmSet || globalDoorsAlarmSet)
{
if (zoneNumber == 1) //Entry zone
{
//kick off a timer after delay specified in Settings1 file,
if (Settings1.Default.alarmSirenDurationInMinutes != 0)
{
//activates the relays if global alarm flags are still set to true
//(i.e. user has not entered code in time)
globalAlarmEntryDurationTicks = 0;
tmrSoundSirensAfterDelay.Start();
}
}
else //If any other zone is activated during alarm set condition
{
if (Settings1.Default.alarmSirenDurationInMinutes != 0)
{
//Output to relays 1 & 2
spIOCard.Write("~out10=1~");
spIOCard.Write("~out11=1~");
//then close after duration from Settings1 file
globalAlarmSirenDurationTicks = 0;
tmrSoundSirens.Start();
}
}
}
}
private void tmrSoundSirensAfterDelay_Tick(object sender, EventArgs e)
{
globalAlarmEntryDurationTicks = globalAlarmEntryDurationTicks + 1;
if (globalAlarmEntryDurationTicks == Settings1.Default.alarmEntryDelayInSeconds) //Value from Settings1 file
{
spIOCard.Write("~out10=1~");
spIOCard.Write("~out11=1~");
globalAlarmEntryDurationTicks = 0;
tmrSoundSirensAfterDelay.Stop();
tmrSoundSirens.Start();
}
}
private void tmrSoundSirens_Tick(object sender, EventArgs e)
{
globalAlarmSirenDurationTicks = globalAlarmSirenDurationTicks + 1;
if (globalAlarmSirenDurationTicks == (Settings1.Default.alarmSirenDurationInMinutes * 5)) //*60 Value from Settings1 file
{
spIOCard.Write("~out10=0~");
spIOCard.Write("~out11=0~");
globalAlarmSirenDurationTicks = 0;
tmrSoundSirens.Stop();
}
}
private void button24_Click(object sender, EventArgs e)
{
globalFullAlarmSet = true;
checkAndActivateRelays(1);
}
Serial Port Data Received Code:
private void spIO_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
RxString = spIOCard.ReadExisting();
if (RxString == "~in00=1~")
{
checkAndActivateRelays(1);
button10.BackColor = System.Drawing.Color.Red;
}
if (RxString == "~in00=0~")
{
button10.BackColor = System.Drawing.Color.LightGray;
}
if (RxString == "~in01=1~")
{
checkAndActivateRelays(2);
button11.BackColor = System.Drawing.Color.Red;
}
if (RxString == "~in01=0~")
{
button11.BackColor = System.Drawing.Color.LightGray;
}
if (RxString == "~in02=1~")
{
button12.BackColor = System.Drawing.Color.Red;
}
if (RxString == "~in02=0~")
{
button12.BackColor = System.Drawing.Color.LightGray;
}
}
Something to think about since you are using the DataReceivedEvent. According to MSDN it is raised on a secondary thread. This is probably causing your issue.
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object. Because this event is raised on a
secondary thread, and not the main thread, attempting to modify some
elements in the main thread, such as UI elements, could raise a
threading exception. If it is necessary to modify elements in the main
Form or Control, post change requests back using Invoke, which will do
the work on the proper thread.
Since calling Start() is not the problem the timer setup is where you need to look. Make sure you handle the tick event AND set an interval.
myTimer.Tick += new EventHandler(TimerEventProcessor);
// Sets the timer interval to 5 seconds.
myTimer.Interval = 5000;
myTimer.Start();
The key here is that you are doing this in the SerialPort DataReceived event. This event is fired on a separate thread. Thats important because you probably registered for the Tick event on the main thread, but you start the timer on a different one. You'll need to register the Tick event in the checkAndActivateRelays function. Then it should be happy.
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
I have a winform app, which shows some information in time, every time it loads the data, I set a delay time of 7 sec like this: System.Threading.Thread.Sleep(7000) so the info can be viewed. I want to have a buttom that allows me to jump to the next information without waiting.
The logic I use is as follows: get Information, if any, wait 7 sec, next data, and so on. So if I press the button I'd like to set that time to 0.
Is there any way to cancel the waiting period?
here is the code:
ManualResetEvent wait_handle = new ManualResetEvent(true);
{...}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
bool hasLines = GetLinesOnProduction();
while (doLoop)
{
wait_handle.WaitOne();
if (hasLines)
{
param1 = Lines[CurrentLine].line;
param2 = Lines[CurrentLine].WO;
//Here I query the DB for the CurrentLine Data
ShowLineInformation(CurrentLine);
ShowChartByHour(param1, param2, out hasInfo);
if (hasInfo)
System.Threading.Thread.Sleep(7000);
//Here I move to the next line
if (CurrentLine < Lines.Count - 1)
CurrentLine++;
else
{
CurrentLine = 0; //Start all over again
hasLines = GetLinesOnProduction();
}
}
else
{
System.Threading.Thread.Sleep(40000); //(No Lines)Wait to query for lines again
hasLines = GetLinesOnProduction();
}
}
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
if (btnPauseResume.Text == "Pause")
{
btnPauseResume.Text = "Resume";
wait_handle.Reset();
}
else
{
btnPauseResume.Text = "Pause";
wait_handle.Set();
}
}
Instead of doing Thread.Sleep, you can use a wait event, and simply set it to cancel the wait. Something like this:
var waiter = new AutoResetEvent(false);
bool wasCanceled = waiter.WaitOne(7000);
if(wasCanceled)
// Jump to next...
// Cancel the wait from another thread
waiter.Set()
Rather than using Thread.Sleep, which will suspend all activity in your UI, use a timer instead. With a timer, the UI can still response to events while your timer callback is pending, and when you click the button, you can cancel the timer.
I would set up the delay by locking an object and then executing a Monitor.Wait on with a delay of 7 seconds. Then, from the form, when the button is pushed, lock the object and do a Monitor.PulseAll.
You could use a ManualResetHandle:
// Declare it as class member
ManualResetHandle _manualResetHandle = new ManualResetHandle();
// Wait in your process for seven seconds, or until it is Set()
_manualResetHandle.WaitOne(7000);
// Set() it in your click event handler:
_manualResetHandle.Set();