I keep getting the following error when debugging.
Cross-thread operation not valid: Control 'richTextBoxReceivedMsg' accessed from a thread other than the thread it was created on.
Here's the code that it points to:
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
int iRx = 0;
// Complete the BeginReceive() asynchronous call by EndReceive() method
// which will return the number of characters written to the stream by the client
iRx = socketData.m_currentSocket.EndReceive (asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
richTextBoxReceivedMsg.AppendText(szData);
// Continue the waiting for data on the Socket
WaitForData( socketData.m_currentSocket);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
Can somebody please help me fix this?
You need to replace this:
richTextBoxReceivedMsg.AppendText(szData);
with something like
Invoke(new Action(() => richTextBoxReceivedMsg.AppendText(szData)));
The reason is that Windows Forms is not really designed to work across different threads. Invoke method will run the delegate you pass to it in the UI thread. If you want to manipulate UI elements via other threads, you'll have to run the actual manipulation on the UI thread. InvokeRequired property will tell you when you need to use Invoke rather than calling the method directly.
check by writing the given statement in your form1() constructor RichTextBox.CheckForIllegalCrossThreadCalls = false;
Thank u....
Related
I try to get data asynchronously from a serial port. Mainly because DataReceived event seems not to be reliable enough and we end up with RXOver errors.
Target is .NET 4.0, so we need to use the older Begin/End methods.
I also learned that it is needed to call BeginRead() within a thread from the ThreadPool, otherwise the initiating thread would have terminated already when processing the passed callback.
However, even with a pooled thread I always get an IOException "The I/O operation has been aborted because of either a thread exit or an application request".
The underlying com port is open.
Any advise welcome.
#region DataReceiving
private readonly byte[] buffer = new byte[MAX_BUFFER_SIZE];
private void StartDataReceiving()
{
ThreadPool.QueueUserWorkItem( state => this.AsyncDataReceiving() );
}
private void AsyncDataReceiving()
{
this.serialPort.BaseStream.BeginRead(
this.buffer, 0, this.buffer.Length,
asyncResult =>
{
try
{
int actualLength = this.serialPort.BaseStream.EndRead( asyncResult );
byte[] received = new byte[actualLength];
Buffer.BlockCopy( this.buffer, 0, received, 0, actualLength );
this.dataConsumer.Add( received );
}
catch (IOException ex)
{
this.HandleSerialError( ex );
}
// Setup receiving action again
this.AsyncDataReceiving();
}
, null );
}
#endregion
I have 2 threads running simultaneously and each is writing to the socket.Send() stream,
While (soc.Connected)
{
byte[] byData = new byte[2];
byData = System.Text.Encoding.ASCII.GetBytes("A");
soc.Send(BitConverter.GetBytes(byData.Length));
soc.Send(byData);
}
The other thread uses the exact same code, except it's sending "1" instead of "A".
How will the data at the other end look like? Will it be either a stream of AAAAAAAA or 111111111s or randomly mixed like A1A1111AAAA1 ?
Should I avoid this way of sending entirely and block the sending until the other thread finishes?
Should I avoid this way of sending entirely and block the sending until the other thread finishes?
Yes and no, you should avoid this entirely but it is not necessary to block sending till the other thread finishes.
What you could do is have a 3rd thread who's responsibility is to send data and your two threads who need to send data put their data on to a thread safe queue. Then the sending thread would dequeue the work to be done and send it out on the wire.
const int MAX_QUEUE_LENGTH = 10;
private BlockingCollection<MyMessageContainer> messageQueue = new BlockingCollection<MyMessageContainer>(new ConcurrentQueue<MyMessageContainer>(), MAX_QUEUE_LENGTH);
void ProcessMessages()
{
foreach (var message in messageQueue.GetConsumingEnumerable())
{
if(soc.Connected == false)
break;
soc.Send(message.ToPaylod());
}
}
void GenerateMessageOne()
{
while(true)
{
messageQueue.Add(new MyMessageContainer("A"));
}
}
void GenerateMessageTwo()
{
while(true)
{
messageQueue.Add(new MyMessageContainer("1"));
}
}
class MyMessageContainer
{
public MyMessageContainer(string message)
{
_message = message;
}
private string _message;
public byte[] ToPayload()
{
var lengthBytes = BitConverter.GetBytes(byData.Length);
return lengthBytes.Concat(() => System.Text.Encoding.ASCII.GetBytes(_message)).ToArray();
}
}
The above code will let both threads queue work at the same time without blocking till the queue reaches a length of MAX_QUEUE_LENGTH, once there calling messageQueue.Add( will now start blocking till the sending thread has had a chance to clear up some room, once room has been made it will unblock one of the functions and let it continue.
If you want randomly-sequenced output, the easiest solution is to simply put a lock around the line that actually writes to the socket. I would also recommend adding a call to Thread.Sleep for fairness, though that is somewhat optional.
While (soc.Connected)
{
byte[] byData = new byte[2];
byData = System.Text.Encoding.ASCII.GetBytes("A");
lock(soc)
{
soc.Send(BitConverter.GetBytes(byData.Length));
soc.Send(byData);
}
Thread.Sleep(0);
}
I'm currently writing a component to communicate with an Ethernet based device and am having to use asynchronous sockets. At times when I receive specific 'commands' from the device, I need to raise an event for whatever program is using my component (most usually a WinForm.) I'm creating a sample form for the user but I am having difficulty allowing the client form to receive the events and modify the form; I'm getting the typical "Cross-thread operation not valid: Control 'listStrings' accessed from a thread other than the thread it was created on."
I've tried reading over Implementing the Event-based Asynchronous Pattern, and Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern, though it doesn't quite seem to be exactly what I need, especially when reading "Opportunities for Implementing the Event-based Asynchronous Pattern" in the first link.
.Net / C# is more of a hobby than profession, and in this project - this is the last piece I need to figure out before being able to complete it. Would it be better to use a "thread-safe" (I know, everyone throws that term around like it only means one thing) existing TCP/IP component rather than trying to implement it myself?
EDIT: Here's my network class code to show you how I'm implementing it now. I forget where I came across this snippet, but it's worked fine up until I've added the form.
internal class Network
{
private Device dev;
private TcpClient client;
private NetworkStream ns;
private byte[] buffer = new byte[2048];
private Queue<byte[]> _msgQ = new Queue<byte[]>();
public Network(Device d)
{
dev = d;
}
internal void Connect(string ipAddress, int port)
{
client = new TcpClient();
client.BeginConnect(ipAddress, port, new AsyncCallback(OnConnect), null);
}
internal byte[] getLocalIp()
{
return ((IPEndPoint)client.Client.LocalEndPoint).Address.GetAddressBytes();
}
private void OnConnect(IAsyncResult ar)
{
try
{
client.EndConnect(ar);
ns = new NetworkStream(client.Client);
ns.BeginRead(buffer, 0, 2048, new AsyncCallback(OnRead), null);
while (_msgQ.Count > 0)
{
byte[] message = _msgQ.Dequeue();
ns.Write(message, 0, message.Length);
}
dev.dvDevice._connected = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
internal void Disconnect()
{
try
{
client.Close();
dev.dvDevice._connected = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
internal void Write(byte[] message)
{
if ((!client.Connected) || ns == null)
{
_msgQ.Enqueue(message);
return;
}
ns.Write(message, 0, message.Length);
}
private void OnWrite(IAsyncResult ar)
{
try
{
ns.EndWrite(ar);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void OnRead(IAsyncResult ar)
{
try
{
int recv = ns.EndRead(ar);
byte[] message = new byte[recv];
Buffer.BlockCopy(buffer, 0, message, 0, recv);
dev.dvDevice._mh.Parse(message);
ns.BeginRead(buffer, 0, 2048, new AsyncCallback(OnRead), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Device is the class which is exposed to the client. It contains a MessageHandler (_mh) class which does all the parsing. Device contains the public event which is called by the MessageHandler on specific responses. Hopefully this helps in what I have so far; I'd prefer not having to rewrite too much, but to make it right (and work properly), I will if I must.
EDIT (2):
My goal for this library is that the user should not at all have to manage any of the threads - so when an event is raised, say "ReceiveString", the user should just be able to act on it without any thought.
EDIT (3):
More code for completeness.
public delegate void OnStringEvent(byte[] str);
public class Device
{
internal struct _device
{
// other stuff too, but here's what's important
public bool _connected;
public bool _online;
public MessageHandler _mh;
public Network _net;
}
public event OnStringEvent OnString;
internal void ReceiveString(byte[] str)
{
OnString(str);
}
internal _device dvDevice;
public Device(int device_number, int system_number)
{
dvDevice = new _device(device_number, system_number);
dvDevice._mh = new MessageHandler(this);
dvDevice._net = new Network(this);
}
}
internal class MessageHandler
{
private Device dev;
public MessageHandler(Device d)
{
dev = d;
}
public void Parse(byte[] message)
{
// The code goes through the message and does what it needs to
// and determines what to do next - sometimes write back or something else
// Eventually if it receives a specific command, it will do this:
dev.ReceiveString(ParseMessage(ref _reader));
}
}
Do youself a favor and rely on TPL to do the synchronization lifting for you. Example:
NetworkStream stream = MySocket.NetworkStream;
// creat a Task<int> returning the number of bytes read based on the Async patterned Begin- and EndRead methods of the Stream
Task<int> task = Task<int>.Factory.FromAsync(
fs.BeginRead, fs.EndRead, data, 0, data.Length, null);
// Add the continuation, which returns a Task<string>.
return task.ContinueWith((task) =>
{
if (task.IsFaulted)
{
ExceptionTextBox.Text = task.Exception.Message;
}
else
{
ResultTextBox.Text = string.Format("Read {0} bytes into data", task.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
I like #Polity's answer, being an Rx fan I would say use Rx (Reactive Extensions)
//we convert a typical begin/end (IAsyncPattern) into an observable sequence
//it returns a Func -read() that takes a byte, two ints and returns one.
var read = Observable.FromAsyncPattern<byte[], int, int, int>
(networkStream.BeginRead, networkStream.EndRead)
.ObserveOn(Scheduler.Dispatcher);
// Now, you can get an IObservable instead of an IAsyncResult when calling it.
byte[] someBytes = new byte[10];
IObservable<int> observable = read(someBytes, 0, 10);
observable.Subscribe(x=>
//x will be the returned int. You can touch UI from here.
);
Based on your code I can see that another thread calls the OnString event, then I assume when you subcribe to it, you're just adding the string into the listbox.
device.OnString += new OnStringEvent(device_onstring);
void device_onstring(byte[] str)
{
listStrings.Items.Add(...);//this is wrong, will give cross thread op error.
//you do this:
this.Invoke(new MethodInvoker(delegate()
{
listStrings.Items.Add(..);
//or anything else that touches UI
});
// this should refer to a form or control.
}
You can handle this in 2 places depending on your design. If the event is raised from a different thread you can handle it in the event handler by checking the .invokeReqeuired property of the form( or other control) handling the event. If it returns true you should use the .beginInvoke method to marshal the call to the proper thread.
Depending on your design you can handle it from the other end by passing your component an instance of the form you want to marshal to. Before you raise the event, check .invokeRequired and marshal the call so that the event is raised in the proper thread. This way the code using your library doesn't have to worry about threads, but it required that your library have a reference to system.windows.forms.
This should be a pretty easy problem to solve: you just need to execute any code in your form that updates controls using Invoke.
The precise implementation will depend on how the async code is calling back into your form. If you add that code to your question, we can provide a more complete answer.
i have a simple windows service which runs and starts a thread which listen/receive heartbeat via tcp/ip. i'm having a hard time finding ways to sync between getting information from the tcp thread and using that value to update something in the main thread.
i try to use a thread.sleep method and keep on looping it for a few times while awaiting the answer back from the thread and then getting the value, but that method seems to be a bit volatile with the method sometimes working and sometimes not.
so what's a good way to sync between these two?
basically what i want to do is to start the listening tcp thread, get specific value and the update the main program.
attached are the receive function and the function which i used to start the thread.
p.s: i'm a totally noobie when it comes to tcp/ip and c# so any comments on any part of the code or the design is more than welcome :)
public virtual void Receive()
{
string eventMessage = string.Empty;
int bytesRcvd = 0;
int totalBytesRcvd = 0;
byte[] byteBuffer = new byte[maxBufferSize];
NetworkStream listenStream;
try
{
if (client.Connected)
{
listenStream = client.GetStream();
}
else
{
return;
}
while (true)
{
//message that is slot in from the object will get sent here.
if (!string.IsNullOrEmpty(MessageToSend))
{
Send(MessageToSend);
MessageToSend = string.Empty;
}
// must convert it back and look for the delimiter, cannot wait for the three heartbeat to pass
string leftoverMsg = string.Empty;
bytesRcvd = listenStream.Read(byteBuffer, totalBytesRcvd, maxBufferSize - totalBytesRcvd);
totalBytesRcvd += bytesRcvd;
//if more than heart beat size, can process to see if it's a heartbeat and proceed to send
if (totalBytesRcvd > msgHeartbeatSize)
{
eventMessage = Encoding.ASCII.GetString(byteBuffer, 0, totalBytesRcvd);
ProcessMessage(eventMessage, ref leftoverMsg, ref totalBytesRcvd, ref byteBuffer);
}
}
}
catch (ThreadAbortException thEx)
{
//do nothing as main thread has aborted and waiting to close
logger.Info(Thread.CurrentThread.Name + " is stopped. ");
}
catch (Exception exce)
{
bIsActive = false;
logger.Error(exce);
CleanUp();
}
finally
{
logger.Info(String.Format("Thread {0} Exiting. ", Thread.CurrentThread.Name));
}
}
public virtual void StartReceivingThread()
{
Thread thrReceive = new Thread(Receive);
try
{
if (!bIsActive && Connect())
{
//NOTE: exception thrown by a thread can only be captured by that thread itself
//start a listen thread
//wait until heartbeat message is accepted
thrReceive.Name = "thr" + serviceType.Name;
thrReceive.Start();
bIsActive = true;
//wait to get the heartbeat message
for (int i = 0; i < maxRetry; i++)
{
Thread.Sleep(maxTimeOutValue);
if (bIsReceivingHeartbeat)
break;
}
//if nothing happens close the connection and try again
if (!bIsReceivingHeartbeat)
{
bIsActive = false;
CleanUp();
logger.Info("Closing receiver thread - " + thrReceive.Name);
}
else
{
logger.Info("Starting receiver thread - " + thrReceive.Name);
}
}
}
catch(Exception ex)
{
logger.Error(ex);
}
//finally
//{
// logger.Info("Exiting receiver thread - " + thrReceive.Name);
//}
}
I assume bIsReceivingHeartbeat is a bool member variable of the class. If the value changed in one thread (receiver) is not visible in the other thread this is most likely due to memory barrier. I am saying this from my Java background but this is most likely true in .net as well.
Try declaring the variables volatile or use a property and make the getter and setter synchronized:
private bool bIsReceivingHeartbeat;
public bool IsReceivingHeartbeat
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return bIsReceivingHeartbeat; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { bIsReceivingHeartbeat = value; }
}
And in the calling code:
if (!IsReceivingHeartbeat) ....
I am writing from Java background but the situation most likely similar
(Looks like you also posted this code in refactormycode.com.)
Anyway, instead of the loop with a sleep delay, I recommend using an Event object that pulsed by the code that sets IsReceivingHeartbeat. See the ManualResetEvent and AutoResetEvent classes in MSDN.
Well I'm making a Client-Server application and I can send messages to my client just fine but when I do it the other way around (Client to server) the server application just closes down, any help on how to fix this?
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
int iRx = 0;
iRx = socketData.m_currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(socketData.dataBuffer,
0, iRx, chars, 0);
System.String szData = new System.String(chars);
area1.AppendText(szData);
WaitForData(socketData.m_currentSocket); // Continue the waiting for data on the Socket
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
After doing some breakpoints I realized it closes after reaching this part when it tries to append it on the textArea it closes without an error.
Any ideas on how to fix this? I guessing something to do with the threads but not sure why it just closes.
Does an exception happen when AppendText is called? If yes, can you include the call stack? Is szData valid data when AppendText is called? Try putting a try/catch around the code to get the exception information:
try
{
... your code...
}
catch (Exception e)
{
... examine 'e' in the debugger or dump it to a log file
}
One thing that might be going wrong is that you are accessing a UI control from the non-UI thread, but it could be other things. It's hard to tell from the code snippet you posted.
Updated:
If the exception was that the control is being invoked from the wrong thread, you can try adding a function like this, then calling that instead of accessing the control directly (untested):
private void AppendText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.area1.InvokeRequired)
{
SetTextCallback d = new AppendTextCallback(AppendText);
this.Invoke(d, new object[] { text });
}
else
{
this.area1.AppendText(text);
}
}