Every time I had problem with my SQL Server connection (ex. someone switch of server) my application will show an exception message in a messagebox. I don't know when will the connection available except I keep trying to open the connection / execute a query.
So I create a wait form that will appear if connection is unavailable, keep trying to open the connection, and close itself when connection is available again.
To hide the freeze from user, I use a background worker.
This is the background worker code
private void StartLoader(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
if (this.par.sqSuccess) //if no error, means connection is available, stop looping
{
break;
}
else
{
i -= 1;
}
System.Threading.Thread.Sleep(5000); //report progress every 5 second
}
This is the background worker's progress changed event
this.cnn = new SqlConnection(this.par.Constr);
try
{
this.cnn.Open(); //SqlConnection
this.par.sqSuccess = true; //if no error, then I change this variable
}
catch (Exception ex)
{
this.par.Exception = ex.Message;
}
finally
{
if (this.cnn != null) { this.cnn.Dispose(); }
}
if (this.par.sqSuccess) { this.Close(); }
After everything is complete, I tried to stop SQL Server service from services.msc, then I try to connect.
The wait form will appear and keep doing its job.
A few second after I try to connect, I start the service again and the wait form did close, success.
This is the problem, when I wait a little bit longer before I start the service again, the wait form still closed, but it takes a while.
After I check everything, it seems like the cnn.open() queue up and the longer I stop the service, the longer it takes for the wait form to close.
I searched google and try to add Connect Timeout=3; behind my connection string, as I'm sure my thread.sleep(5000) won't make them queue up, but still not working.
Someone told me to use cnn.OpenAsync();
After reading the documentation about OpenAsync, this is what I do.
static async Task<ConnectionState> Method(SqlConnection cnn)
{
await cnn.OpenAsync();
return cnn.State;
}
And this
private void SQLClientLoader_Load(object sender, EventArgs e)
{
do
{
this.cnn = new SqlConnection(this.par.Constr);
try
{
ConnectionState cst = Method(cnn).Result;
if (cst == ConnectionState.Open)
{
this.par.sqSuccess = true;
}
else
{
}
}
catch (Exception ex)
{
this.par.sqSuccess = false;
this.par.Exception = ex.Message;
}
finally
{
}
} while ((bool)this.par.sqSuccess != true);
}
The code above freezes my application every time the form load code executed.
I need simple instruction of how to wait for the cnn.Open process to finish or to cancel it if it takes too long.
Thank you in advance
You can set the ConnectionTimeout property for your SqlConnection in your code or in your ConnectionString. No need to use Async IMHO..
cnn.ConnectionTimeout = 5000
So this will create about a 10-second delay if connection does not work (connectiontimeout + Sleep(5000).
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.
My program works like this:
I press a radio button which opens the port.
Next i press a button "Read" which starts a thread that reads data continously from the Serial Port using port.ReadLine() and prints it in a textbox;
I have another radio which should first join the thread and after that close the port;the problem is the printing goes well until i close the port when the UI freezes.
public Form1()
{
mythread = new Thread(ReadFct);
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
Below is the function attached to the thread
void ReadFct()
{
string aux = "";
while (readCondition)
{
if (myPort.IsOpen)
aux = myPort.ReadLine();
this.SetText(aux);
}
}
Below is the radio button event handler
public void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
try
{
myPort.Open();
mythread.Start();
}
catch (Exception)
{
MessageBox.Show("Nu s-a putut deschide port-ul");
}
if (radioClose.Checked && myPort.IsOpen)
{
readCondition = false;
mythread.Join();
myPort.Close();
// myPort.DataReceived -= DataReceivedHandler;
}
}
The read button function:
private void readbtn_Click(object sender, EventArgs e)
{
if (!myPort.IsOpen)
MessageBox.Show("PORT NOT OPENED!");
else
{
// myPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
readCondition = true;
if (!mythread.IsAlive)
{
mythread = new Thread(ReadFct);
mythread.Start();
}
}
I have used what MSDN suggest when changing control from another thread:
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
StringTb del = new StringTb(SetText);
this.Invoke(del, new object[] { text });
}
else
SetData = text;
}
It's hard to know exactly what you need, lacking a good Minimal, Complete, and Verifiable code example to illustrate the question. That said, the issue here is that the Thread.Join() method causes that thread to stop doing any other work, and the thread you use to call that method is the thread that handles all of the user interface. Worse, if your port never receives another newline, the thread you're waiting on will never terminate, because you're stuck waiting on the ReadLine() method. Even worse, even if you do get a newline, if that happens while you're stuck waiting on the Thread.Join(), the call to Invoke() will deadlock, because it needs the UI thread to do its work, and the Thread.Join() call is preventing it from getting the UI thread.
In other words, your code has multiple problems, any one of which could cause problems, but all of which together mean it just can't possibly work.
There are a variety of strategies to fix this, but IMHO the best is to use await. The first step in doing that is to change your I/O handling so that it's done asynchronously instead of dedicating a thread to it:
// Ideally, you should rename this method to "ReadFctAsync". I am leaving
// all names intact for the same of the example though.
async Task ReadFct()
{
string aux = "";
using (StreamReader reader = new StreamReader(myPort.BaseStream))
{
while (true)
{
aux = await reader.ReadLineAsync();
// This will automatically work, because the "await" will automatically
// resume the method execution in the UI thread where you need it.
this.SetText(aux);
}
}
}
Then, instead of creating a thread explicitly, just create a Task object by calling the above:
public Form1()
{
// In this approach, you can get rid of the "mythread" field altogether
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
public async void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
{
try
{
myPort.Open();
await ReadFct();
// Execution of this method will resume after the ReadFct() task
// has completed. Which it will do only on throwing an exception.
// This code doesn't have any continuation after the "await", except
// to handle that exception.
}
catch (Exception)
{
// This block will catch the exception thrown when the port is
// closed. NOTE: you should not catch "Exception". Figure out what
// *specific* exceptions you expect to happen and which you can
// handle gracefully. Any other exception can mean big trouble,
// and doing anything other than logging and terminating the process
// can lead to data corruption or other undesirable behavior from
// the program.
MessageBox.Show("Nu s-a putut deschide port-ul");
}
// Return here. We don't want the rest of the code executing after the
// continuation, because the radio button state might have changed
// by then, and we really only want this call to do work for the button
// that was selected when the method was first called. Note that it
// is probably even better if you just break this into two different
// event handlers, one for each button that might be checked.
return;
}
if (radioClose.Checked && myPort.IsOpen)
{
// Closing the port should cause `ReadLineAsync()` to throw an
// exception, which will terminate the read loop and the ReadFct()
// task
myPort.Close();
}
}
In the above, I have completely ignored the readbtn_Click() method. Lacking a good MCVE, it's not clear what role that button plays in the overall scheme. You seem to have a radio button group (of two buttons) that control whether the port is open or closed. It is not clear why then you have an additional regular button that is seemingly able to also open the port and start reading, independently of the radio group.
If you want that extra button, it seems to me that all it ought to do is change the radio group state, by checking the "open" radio button. Then let the radio group buttons handle the port state and reading. If you need more specific advice as to how to fully integrate my code example above with your entire UI, you will need to provide more detail, preferably in a new question. That new question must include a good MCVE.
I'm working on a program that's supposed to establish "n" many SSH connections with a remote Linux server, and run time consuming commands on each connection. The "time consuming operation" is basically running a script that sets up Wireshark and listens to the traffic.
For this I'm using the SharpSSH library for C# and n many BackgroundWorkers as threads. Also for simplicity, the code below has n=2 BGW threads and SSH connections.
Code:
// runs when start is pressed
private void startButton_Click_1(object sender, EventArgs e)
{
sb = new StringBuilder();
DateTime timeNow = DateTime.Now;
clickTime = timeNow.ToString("yyyyMMddhhmmssfff"); // store the exact time of the click
bw = bwArray[0];
int index = 0; // ignore these 2 constants
foreach (BackgroundWorker bgw in bwArray)
{
if (bgw.IsBusy != true)
{
bgw.RunWorkerAsync();
// runWorkerAsync for every BackgroundWorker in the array
//index++;
}
}
}
// runWorkerAsync leads the BGWorker to this function
private void bw_doWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker.CancellationPending == true)
{
e.Cancel = true;
}
else
{
// let the UI know of button changes
int p = 0;
object param = "something"; // use this to pass any additional parameter back to the UI
worker.ReportProgress(p, param);
// UI notifying part ends here
// for the simplex case
if (numberOfConnections == 1)
startOperation();
// for the multiplex case
else if (numberOfConnections > 1)
{
//while (p < numberOfConnections)
//{
multiStartOperation();
// p++;
//}
}
Thread.Sleep(500);
}
}
// will be called for all ssh connections (in multiplex case)
private void multiStartOperation()
{
string[] command1Array = { "host2", "host2" };
string[] command2Array = { clickTime + "_h2", clickTime + "_h2" };
for (int index = 0; index < numberOfConnections; index++)
{
// shellArray is an array of SshExec objects
shellArray[index] = new SshExec(IPAddress, username, password);
try
{
shellArray[index].Connect();
}
catch (JSchException se)
{
Console.Write(se.StackTrace);
System.Windows.Forms.MessageBox.Show("Couldn't connect to the specified port.", "Connection Error!");
}
sb.Append(shellArray[index].RunCommand(command1Array[index]) + Environment.NewLine);
// first command is host3, or host4 etc.
// below is the time consuming command to run
string command = "./logcap.sh -c " + command2Array[index] + " -z";
// sb is a global stringBuilder object,
// to which the command output is appended
sb.Append(shellArray[index].RunCommand(command));
}
}
My problem is the following:
When I press the start button on the GUI, both connections should start and run the script. Whereas in the code given above, the first index of shellArray (which consists of SshExec objects) gets connected, prepares the commands and runs the time consuming command, at which point the program goes back to the UI, without even starting the second connection. This is obviously because of the for loop, but I couldn't figure out how to work around this yet.
I need to get the other backgroundworker to establish and run the second command with the second server, so that when I press the stop button on the GUI all connections and threads can stop all together.
PS: The commands will not stop running unless the user clicks stop, which sends a Ctrl-C signal to the server.
I'm relatively new to all the multithreading and networking concepts, so if there is any confusion or mistake please let me know.
Have a nice day.
Thank you for your answers, and the welcome. :)
The problem indeed was not being able to run multiple backgroundworkers at the same time.
I managed to solve the issue. It turns out that all I had to figure out was how to assign backgroundworkers to SSH connections. To do that, I created a class as follows:
class BGW
{
private BackgroundWorker bgw;
private int index;
//getters, setters, constructors...
}
After this, I converted bwArray which was an array of BackgroundWorkers into an array of BGW objects. At initialization, I assigned each BGW object an index.
Instead of having the stupid loop within multiStartOperation(), I sent an integer parameter to multiStartOperation() and that function used that index to reach the allocated backgroundworker.
So far it seems to work.
Have a nice day.
I have a problem using Thread.sleep(seconds), it pauses all my execution in sleeping state. But I tried another solutions also using for loop, however what I'm expecting it's not working.
When the login button is clicked:
Action report="on progressing";
After another 2 seconds it will be "trying to connect to the database"
then after opening database it will be like "database connected successfully"
Here is the code:
private void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(userText.Text!=String.Empty && passText.Password!=String.Empty){
ProgressForm.Visibility = System.Windows.Visibility.Visible;
LoginForm.Visibility = System.Windows.Visibility.Hidden;
delay(2);
actionReport.Text = "Try to Connecting the database";
String ConnectionString = "server=127.0.0.1;uid=root;pwd='';database=smsdb;";
MySqlConnection con = new MySqlConnection(ConnectionString);
try {
con.Open();
delay(2);
actionReport.Text = "Database Connected Sucessfully";
}
catch(MySqlException sqle){
actionReport.Text = sqle.Message;
}
}
else {
MessageBox.Show("Please enter the user name and password to verify","Notification",MessageBoxButton.OK,MessageBoxImage.Information);
}
}
private void delay(int seconds)
{
for(long i=0;i<seconds*3600; i++){
//empty
}
Please someone help me.
await (introduced in C# 5.0) with Task.Delay makes this trivially easy:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
await Task.Delay(2);
actionReport.Text = "Connected";
}
For a C# 4.0 solution it's a tad messier, but not a whole lot:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
Task.Delay(2).ContinueWith(_ =>
{
actionReport.Text = "Connected";
}, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
The key point here is that at no point are you blocking the UI thread, you're simply letting the UI thread continue on processing events for two seconds before giving it something to do.
I found answer like this
delay("Try to Connecting the database");
delay like this.
public void delay(string message) {
var frame = new DispatcherFrame();
new Thread((ThreadStart)(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(2));
frame.Continue = false;
})).Start();
Dispatcher.PushFrame(frame);
actionReport.Text=message;
}
Thanks friends!
to reply me.
You first need to look up and understand performing processing on a background thread. The main rules being;
You should never block the UI
don't try to talk to the UI thread from a background thread
If you call Thread.Sleep, it's probably wrong
Your questions demonstrate an opportunity for you to learn new architectural patterns. These look like good candidates;
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners
http://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-1-of-n
I have implemented my custom ThreadManager which has been working flawlessly during my tests. When user wants to close the application, the closing is suspended until all threads exit or they select to end the application without waiting (after 30 seconds have passed).
What I need to clarify is if using Application.DoEvents() could be dangerous in FormClosing event. Shall I use it or find another way of waiting for threads to exit?
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// save settings before exit
Properties.Settings.Default.Save();
// Update program about intention
Program.ApplicationClosing = true;
try
{
// Inform user with friendly message
ShowModalWaitForm("Application is closing.");
// Keep the timestamp in order to keep track of how much time has passed since form closing started
DateTime startTime = DateTime.Now;
// Wait for all threads to die before continuing or ask user to close by force after 30 seconds have passed
// In case user prefers to wait the timer is refreshed
int threadsAlive;
do
{
if (_threadManager.TryCountAliveThreads(out threadsAlive) && threadsAlive > 0)
{
Application.DoEvents();
Thread.Sleep(50);
}
TimeSpan timePassed = DateTime.Now - startTime;
if (timePassed.Seconds > 30)
{
if (ShouldNotWaitThreadsToExit())
{
break; // Continue with form closing
}
else
{
startTime = DateTime.Now; // Wait more for threads to exit
}
}
} while (threadsAlive > 0);
}
catch (Exception ex)
{
_logger.ErrorException("MainForm_FormClosing", ex);
}
finally
{
HideWaitForm();
}
}
private bool ShouldNotWaitThreadsToExit()
{
return MessageBox.Show(#"Press ""OK"" to close or ""Cancel"" to wait.", "Application not responding ", MessageBoxButtons.OKCancel) == DialogResult;
}
I'd recommend putting your wait condition in another thread. Display a modal dialog from OnFormClosing method. Inside this dialog start worker thread e.g using BackGroundWorker class and dismiss this dialog when waiting finished.
Bonus topic possible drawbacks of calling Application.DoEvents Method