I have a connection with an IRC server over TCP. I read the data with an independent task, so far, so good. However, if I want to quit the program, I can't quit the thread because it is stuck in the reader.ReadLine() command (threadShouldRun has no impact). Using Interrupt() or Abort() doesn't appear to change anything either.
Either I need a way to determine when there are more lines to read, or I need to forcefully kill the thread (even though that's bad).
private System.Threading.Thread myThread;
private bool threadShouldRun = true;
private StreamReader reader;
private void readStream()
{
while(threadShouldRun)
{
string line = reader.ReadLine();
if (line != null)
{
newLineEvent(this, new NewLineEventArgs(line));
}
}
}
Use asynchronous calls like BeginRead as shown here and avoid the loop:
http://msdn.microsoft.com/en-us/library/system.io.stream.beginread.aspx
A solution would be to set a TimeOut on your receiving socket ( http://msdn.microsoft.com/it-it/library/system.net.sockets.socket.receivetimeout(v=vs.110).aspx ).
Once the time expires, a SocketException will be raised, so you can catch it and reiterate the control on your threadShouldRun.
In case you want to quit (and hence set threadShouldRun to false), there are two scenarios:
Data received, you will handle it, and on the next check the variable will be found false and thread will terminate;
No Data received, TimeOut happens, Exception is raised, you will handle it, and on the check the thread will terminate.
Related
Okay well, here is the code:
private void Receivev2()
{
try
{
using (UdpClient udpclient = new UdpClient(1500))
{
while (connect == true)
{
byte[] byteData = udpclient.Receive(ref remoteEP);
waveProvider.AddSamples(byteData, 0, byteData.Length);
if (Record == true)
{
waveWriter.Write(byteData, 0, byteData.Length);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "VoiceChat-Receive ()", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
It´s on a Thread, and well, it receives data from udp and plays it, nothing weird.
My problem however, is to make it stop normally, or well, don´t know how to put it.
But let´s say, i start the thread and it loops.
Then if i close my application, the application won´t "close", as the thread isn´t closing.
Now to solve that, i use IsBackground = true.
But i am not sure if that is an optimal way to do it, it feels like it will just force it to shut down, like ProcessKill or something.
Maybe it is the correct way, i don´t know.
Please give me advice on this.
The trick is call UdpClient.Close. This will cancel any pending operations and "poke" the Receive method into throwing a SocketException if it is blocking. Obviously, you will have to call Close from another thread which means you will need to refactor your code a bit so that udpclient is no longer a local variable. You will also need to set connect to false so that the loop ends.
So to summarize the steps are as follows.
Call Close to prevent Receive from blocking.
Set connect to false.
Refactor your code to make the above possible.
If it's a import thread, you'd better not set IsBackground , because the main thread stop,It will be forced stop
stop thread step:
1 set connect=false ,than main thread sleep a while untill it stop
2 if the thread still alive, you can abort it ,this step is not necessary
3 than join the back thread to main thread
just like this:
connect= false;
Thread.Sleep(200);
if (thread1 != null)
{
if (thread1 .IsAlive)
{
thread1 .Abort();
thread1 .Join();
}
}
I am trying to do a request-response communication module in c#, using a SerialPort. The
This is a very simple implementation, just to demonstrate that it kinda-works (SerialPort is not working properly (it is a USB virtual COM port), and sometimes eats a few characters, probably some windows driver bug).
However the demo does not work :-/
When Using a propertygrid on the form, which reads out properties of an object, which in turn sends a request to read a property from the remote device, something very strange happens: More than one simulteneous call to SendCommand is made at once.
I tried using a lock{} block to make the calls sequenctial, but it does not work. Even with the lock, more than one call is enters the protected area.
Can you please tell me what am I doing wrong?
My code:
SerialPort sp;
public byte[] SendCommand(byte[] command)
{
//System.Threading.Thread.Sleep(100);
lock (sp)
{
Console.Out.WriteLine("ENTER");
try
{
string base64 = Convert.ToBase64String(command);
string request = String.Format("{0}{1}\r", target_UID, base64);
Console.Out.Write("Sending request... {0}", request);
sp.Write(request);
string response;
do
{
response = sp.ReadLine();
} while (response.Contains("QQ=="));
Console.Out.Write("Response is: {0}", response);
return Convert.FromBase64String(response.Substring(target_UID.Length));
}
catch (Exception e)
{
Console.WriteLine("ERROR!");
throw e;
}
finally
{
Console.Out.WriteLine("EXIT");
}
}
}
The output:
ENTER
Sending request... C02UgAABAA=
Response is: cgAABAAARwAAAA==
EXIT
ENTER
Sending request... C02UgQARwA=
ENTER
Sending request... C02UgAABAA=
Response is: gQARwAAPHhtbD48bWVzc2FnZT5IZWxsbyBYWDIhPC9tZXNzYWdlPjxkZXN0aW5haXRvbj5NaXNpPC9kZXN0aW5hdGlvbj48L3htbD4=
Notice the two ENTER-s, without an EXIT between them? How is that possible?
You need to keep in mind what the lock keyword does, it allows only one thread to enter the lock. Problem is, you are not using any threads. All of this code runs on the UI thread, the main thread of your program.
The next detail you need to know is that the UI thread is special, it is re-entrant. The sp.ReadLine(); call is going to block the UI thread. That is illegal, the UI thread of a GUI program operates as a "single threaded apartment", enabled by the [STAThread] attribute on your program's Main() method. The contract of an STA thread forbids it from blocking, that's very likely to cause deadlock.
To follow the requirements of an STA, the CLR does something special whenever code that runs on the UI thread performs a blocking operation, like SerialPort.ReadLine() does. It pumps a message loop to ensure that messages that Windows sends keep getting dispatched. That message loop does the same thing that Application.Run() does.
Maybe you can see where this is heading, the PropertyGrid is allowed to again call your SendCommand() method. The lock doesn't work at all, this happens on the same thread.
Solving this problem isn't so easy, we can't see the code that gets SendMessage() triggered. But you will need to prevent this from happening, somehow. More background on this behavior in this question.
Where is the field sp assigned? Locks only work on non-null objects.
If sp is assigned differently on each call, then the lock won't be mutually exclusive (locks are only mutually exclusive on the same object instance). In that case, you'd need to have a static field to be used for locking:
private static readonly object _lockObject = new object();
Edit: I see now based on comments in other answers that you are actually running this logic on the UI thread, which is causing the lock to be re-entered multiple times on the same thread (the UI thread) when the message queue is pumped. Run this code on a different thread, and you will gain two advantages: (1) the UI will not lock up as this potentially long-running code executes, and (2) the lock will always be acquired on a new thread, ensuring that subsequent calls to SendCommand will all be on their own thread, and thus enter the lock sequentially as desired.
There are two things you should try/change:
1.Make a separate field, that will be used for locking only
2.Apply the double lock check : double check locking
SerialPort sp;
public byte[] SendCommand(byte[] command)
{
//System.Threading.Thread.Sleep(100);
lock (sp)
{
Console.Out.WriteLine("ENTER");
try
{
string base64 = Convert.ToBase64String(command);
string request = String.Format("{0}{1}\r", target_UID, base64);
Console.Out.Write("Sending request... {0}", request);
sp.Write(request);
string response;
do
{
response = sp.ReadLine();
} while (response.Contains("QQ=="));
Console.Out.Write("Response is: {0}", response);
return Convert.FromBase64String(response.Substring(target_UID.Length));
}
catch (Exception e)
{
Console.WriteLine("ERROR!");
throw e;
}
finally
{
Console.Out.WriteLine("EXIT");
}
}
}
I'm experiencing a weird behavior while trying to stop a SerialPort: the DataReceived event continues to fire after unsubscribing and after calling close! (see StopStreaming in the following code). As a result, in my event handler code I get an InvalidOperationException with the message that "The port is closed".
What am I missing? What is the correct way to close the port and stop the events?
EDIT: I get this error every time I run my code. So this is not a race condition that happens randomly but rather a systematic problem indicating a completely broken code! However, I fail to see how...
private SerialPort comPort = new SerialPort();
public override void StartStreaming()
{
comPort.Open();
comPort.DiscardInBuffer();
comPort.DataReceived += comPort_DataReceived;
}
public override void StopStreaming()
{
comPort.DataReceived -= comPort_DataReceived;
comPort.Close();
isStreaming = false;
}
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Chars)
{
SerialPort port = (SerialPort)sender;
int N = comPort.BytesToRead;
for (; N > 0; N--)
{
byte b = Convert.ToByte(comPort.ReadByte());
//... process b
}
}
}
EDIT: following the suggestions, I changed StopStreaming code to something like this:
public override void StopStreaming()
{
comPort.DataReceived -= comPort_DataReceived;
Thread.Sleep(1000);
comPort.DiscardInBuffer();
Thread.Sleep(1000);
comPort.Close();
isStreaming = false;
}
It seems to work now but I'm not really that happy. I wish there was a more effective way to remove the callback rather than inserting sleep periods in the program.
Your DataReceived event handler is called on a threadpool thread. And yes, they've got the awkward habit of running your code at an unpredictable time, it is not instant. So it is fairly inevitable that, if the device is actively sending data, that it can race with your Close() call and run after you closed it. Unsubscribing doesn't fix it, the threadpool thread already got its target method.
Do realize what you are doing to trigger this problem, you are closing the port while the device is sending data. That's not great, it is guaranteed to cause data loss. But not unlikely to happen when you are debugging your code since you don't actually care about the data.
A counter-measure is to turn off handshaking so the device cannot send anything anymore. Discard the input buffer. Then sleep for a while, a second or two, to ensure that any threadpool threads in-flight have completed running. Then close the port. A very pragmatic one is to simply not close the port, Windows will take care of it when your process terminates.
Looks like multi-threading issue.
SerialPort.DataReceived is raised in a worker thread from thread pool. You're closing port from the thread, that differs from the thread, where SerialPort.DataReceived raised in.
You can handle InvalidOperationException or write some synchronization code to solve this problem.
Update.
The problem is that if your devices sends data intensively, SerialPort queues more and more work items to thread pool. Even if your code will sleep any time before Close, it can be not enough. Unfortunately, SerialPort has an ugly implementation. It hasn't an option, which could tell "please, stop spam me with your data".
Hence, the concrete solution depends on device's protocol and handshaking parameters.
I had the same problem in an application I've been working on. It's exciting to read here about how the threadpool can bring it about.
Before I tracked down it's source though, I found that enclosing the contents of the DataReceived event handler in a try catch statement written in anticipation of the problem was a very effective way to solve it. Now that I know there's not really anything I can do to prevent the issue if I need/want to close a SerialPort while still receiving data, I'm quite happy with this approach.
I had similar issue when the user attempted to Exit application whilst it was still receiving data from the connected device. Application was throwing a System.IO.IOException following call to Me.Close().
Simplest solution I found was to set the SerialPort ReceivedBytesThreshold to a large number in the _FormClosing event handler. This reduces the frequency of DataReceived events and provides time for the Close() call to complete whilst the DataReceived event handler is inactive.
I'm having a problem with a TcpClient closing with a send timeout in a multi-threaded application after the connection has been open for a long period of time (several hours or overnight). The NetworkStream is being used by two threads, a UI thread and a background thread. There is a StreamReader used for reading incoming data, and a StreamWriter used for outgoing data. The StreamReader is only ever accessed one thread (the background one), but the StreamWriter is accessed by both the UI thread and the background thread.
What happens is that if I open a connection and connect to a remote server, I can immediately send and receive data without any problems. I do not get any send timeouts and data is correctly sent and received. However, if I then walk away and do not send any data for several hours and then return and start sending data (this is a chat application if that helps make it make sense), the socket will timeout on the send. During the time that I walk away there is no problem at all receiving data. Additionally, the remote server polls for an active connection and my client must respond to that, and since the connection is open for several hours it must be correctly sending a response. This polling response is only sent on the background thread, though. Data I enter is sent from the UI thread, and that's where the timeout occurs.
I'm guessing it's something to do with concurrent access, but I can't figure out what's causing it and why I can initially send data from the UI without a problem and only have it timeout after being idle for several hours.
Below is the relevant code. The variables at the top are declared in the class. Address and Port are properties in the class. WriteLine is the only method anywhere in the application that sends data with the StreamWriter. I put a lock around the call to StreamWriter.WriteLine hoping that would correct any synchronization issues. WriteLine is called from the background thread inside ParseMessage, and elsewhere from the UI.
If I increase TcpClient.SendTimeout to something larger, that doesn't fix anything. It just takes longer for the socket to timeout. I can't have the background thread both read and write because the background thread is blocking on ReadLine, so nothing would ever get written.
private TcpClient _connection;
private StreamWriter _output;
private Thread _parsingThread;
private object _outputLock = new object();
public void Connect(string address, int port)
{
Address = address;
Port = port;
_parsingThread = new Thread(new ThreadStart(Run));
_parsingThread.IsBackground = true;
_parsingThread.Start();
}
private void Run()
{
try
{
using (_connection = new TcpClient())
{
_connection.Connect(Address, Port);
_connection.ReceiveTimeout = 180000;
_connection.SendTimeout = 60000;
StreamReader input = new StreamReader(_connection.GetStream());
_output = new StreamWriter(_connection.GetStream());
string line;
do
{
line = input.ReadLine();
if (!string.IsNullOrEmpty(line))
{
ParseMessage(line);
}
}
while (line != null);
}
}
catch (Exception ex)
{
//not actually catching exception, just compressing example
}
finally
{
//stuff
}
}
protected void WriteLine(string line)
{
lock (_outputLock)
{
_output.WriteLine(line);
_output.Flush();
}
}
The blocking methods (Read and Write) of the NetworkStream class are not designed to be used concurrently from multiple threads. From MSDN:
Use the Write and Read methods for simple single thread synchronous blocking I/O. If you want to process your I/O using separate threads, consider using the BeginWrite and EndWrite methods, or the BeginRead and EndRead methods for communication.
My assumption is that, when you call WriteLine (and, internally, NetworkStream.Write) from your UI thread, it would block until the concurrent ReadLine (internally, NetworkStream.Read) operation completes in the background thread. If the latter does not do so within the SendTimeout, then the Write would time out.
To work around your issue, you should convert your implementation to use non-blocking methods. However, as a quick hack to first test whether this is really the issue, try introducing a DataAvailable poll before your ReadLine:
NetworkStream stream = _connection.GetStream();
StreamReader input = new StreamReader(stream);
_output = new StreamWriter(stream);
string line;
do
{
// Poll for data availability.
while (!stream.DataAvailable)
Thread.Sleep(300);
line = input.ReadLine();
if (!string.IsNullOrEmpty(line))
{
ParseMessage(line);
}
}
while (line != null);
line = input.ReadLine();
I am using the thread.Abort method to kill the thread, but it not working. Is there any other way of terminating the thread?
private void button1_Click(object sender, EventArgs e)
{
if (Receiver.IsAlive == true)
{
MessageBox.Show("Alive");
Receiver.Abort();
}
else
{
MessageBox.Show("Dead");
Receiver.Start();
}
}
I am using this but every time I get the Alive status, Receiver is my global thread.
The reason it's hard to just kill a thread is because the language designers want to avoid the following problem: your thread takes a lock, and then you kill it before it can release it. Now anyone who needs that lock will get stuck.
What you have to do is use some global variable to tell the thread to stop. You have to manually, in your thread code, check that global variable and return if you see it indicates you should stop.
You can kill instantly doing it in that way:
private Thread _myThread = new Thread(SomeThreadMethod);
private void SomeThreadMethod()
{
// do whatever you want
}
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
private void KillTheThread()
{
_myThread.Abort();
}
I always use it and works for me:)
You should first have some agreed method of ending the thread. For example a running_ valiable that the thread can check and comply with.
Your main thread code should be wrapped in an exception block that catches both ThreadInterruptException and ThreadAbortException that will cleanly tidy up the thread on exit.
In the case of ThreadInterruptException you can check the running_ variable to see if you should continue. In the case of the ThreadAbortException you should tidy up immediately and exit the thread procedure.
The code that tries to stop the thread should do the following:
running_ = false;
threadInstance_.Interrupt();
if(!threadInstance_.Join(2000)) { // or an agreed resonable time
threadInstance_.Abort();
}
thread will be killed when it finish it's work, so if you are using loops or something else you should pass variable to the thread to stop the loop after that the thread will be finished.
C# Thread.Abort is NOT guaranteed to abort the thread instantaneously. It will probably work when a thread calls Abort on itself but not when a thread calls on another.
Please refer to the documentation: http://msdn.microsoft.com/en-us/library/ty8d3wta.aspx
I have faced this problem writing tools that interact with hardware - you want immediate stop but it is not guaranteed. I typically use some flags or other such logic to prevent execution of parts of code running on a thread (and which I do not want to be executed on abort - tricky).