Update main thread from worker without a dispatcher - c#

This have probably been asked before, but I cant find the right answer.
I have a dll that runs a pipe in it's own thread. I use that dll in a Unity project, but the messages I push to Unity end up as exception, due to I don't call them from the main thread. So I need some help implementing this right. Here's how I start the background worker:
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
client.Connect();
while (_isWorkerRunning)
{
using (var sr = new StreamReader(client))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
// TODO send message to Unity in main thread
}
}
if (!client.IsConnected)
{
client.Connect();
}
}
client.Flush();
client.Close();
client.Dispose();
};
worker.RunWorkerAsync();
My pipe client runs in a thread, I have a public event that fires the messages to Unity. But i need to ensure the messages is dispatched. And I am not sure how to do this the right way?

I found a simple solution, where I use a shared buffer across the threads. So my pipe look like this:
private void PipeClientWorker()
{
//Client
var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
client.Connect();
while (_isWorkerRunning)
{
using (var sr = new StreamReader(client))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
// TODO figure out how to do this in the right thread
if (KinectHandler != null)
{
KinectHandler.BeginInvoke(temp, null, null);
}
}
}
if (!client.IsConnected)
{
client.Connect();
}
}
client.Flush();
client.Close();
}
And I start it normally:
var thread = new Thread(PipeClientWorker) {Name = "Pipe Worker Thread", IsBackground = true};
thread.Start();
In Unity I've created a KinectController that puts the messages in a stack, and in the Update loop pops them to a single LastMessage string:
public string LastMessage;
private KinectReader _kinectReader;
private volatile Stack<string> _messageStack;
// Use this for initialization
void Start ()
{
_messageStack = new Stack<string>();
LastMessage = "";
// init Kinect Reader
_kinectReader = new KinectReader();
_kinectReader.StartPipeReader();
_kinectReader.KinectHandler += _kinectReader_KinectHandler;
}
void _kinectReader_KinectHandler(string message)
{
_messageStack.Push(message);
}
// Update is called once per frame
void Update ()
{
// Update Last message
while (_messageStack.Any())
{
LastMessage = _messageStack.Pop();
Debug.Log(LastMessage);
}
}
void OnApplicationQuit()
{
Debug.Log("Stoping the pipe client");
_kinectReader.Stop();
Debug.Log("Qutting application");
}
If anyone have similar issues or have solved it different I would like to discuss the solution :)

Try Thread Ninja. With it you can run background jobs in a coroutine style.

Related

Implement UDP communication without blocking UI

I currently have a partly synchronous (poor) implementation of UDP communication between my android App and a hardware which is broadcasting UDP packets. The App continuously polls the hardware for status information which then is used to update the UI. The App also has various screens, each requesting (only when user switches screens, not continuous) a different set of configuration information. The user can also make changes to the configurations and load them to the hardware. All this while, the status updates keeps running in the background. I am looking for a solution best suited to my scenario.
Here is what I have done so far (simplified to make it more readable)
void InitializeUDP()
{
udpClient = new UdpClient(15001);
sender = default(IPEndPoint);
ThreadPool.QueueUserWorkItem(o => UDP_StatusCommunicator());
udpClient.EnableBroadcast = true;
udpClient.Client.ReceiveTimeout = 500;
}
void UDP_StatusCommunicator()
{
while (true)
{
if (update_flag)
{
try
{
sent_packet = FrameGenerator(frame_Queue[screen], true); //Creates UDP Packet
//CheckQuery(sent_packet);
udpClient.Send(sent_packet, sent_packet.Length,"192.168.4.255", 15000);
received_packet = udpClient.Receive(ref sender);
//CheckResponse(received_packet);
RunOnUiThread(() =>
{
Update_UI(received_packet);
});
}
catch (SocketException e)
{
Console.Writeline("Socket Timeout: " + e);
}
}
Thread.Sleep(update_delay);
}
}
void UDPReadWrite(int screen, bool reading)
{
SelectFunctionQueue(screen); //Select the frames according to the screen selected
//CheckQueue(frame_Queue);
for (int i = 0; i < frame_Queue.Length; i++)
{
try
{
sent_packet = FrameGenerator(frame_Queue[i], reading);
//CheckQuery(sent_packet);
udpClient.Send(sent_packet, sent_packet.Length, "192.168.4.255", 15000);
received_packet = udpClient.Receive(ref sender);
//CheckResponse(received_packet);
if (sent_packet[2] == received_packet[2]) //Verify correct packet received
{
Update_UI(received_packet);
}
else
{
i--; //retry
}
}
catch (SocketException e)
{
Console.WriteLine("Socket Timeout: " e);
i--;
}
}
}
}
void Switch_Screen(int new_screen)
{
update_flag = false;
UDPReadWrite(new_screen, true)
update_flag = true;
}
void User_Config_Write(int screen, byte[] data)
{
update_flag = false;
Update_Payload(data);
UDPReadWrite(screen, false)
update_flag = true;
}
As you would have clearly noticed, this is a very flawed implementation. I keep running into issues like UI freeze, same socket usage being attempted by two threads simultaneously, stuck while waiting for packets. I have tried to use 'async await' but I am not implementing it correctly resulting in race conditions and what not. Any help would be appreciated
Update : After some research and testing I have found the below to be working satisfactorily. However, I would appreciate if someone could just verify whether it has been done correctly
UdpClient udpClient = new UdpClient();
UdpClient r_UdpClient = new UdpClient(15001);
IPEndPoint sender = default(IPEndPoint);
ManualResetEventSlim receive = new ManualResetEventSlim(true);
Task.Run(() => UDP_Transmit());
async void UDP_Transmit()
{
byte[] frame;
SelectFrameQueue(selector);
udpClient = new UdpClient(15001);
udpClient.EnableBroadcast = true;
udpClient.BeginReceive(new AsyncCallback(UDP_Receive), udpClient);
while (true)
{
for (int i = 0; i < frame_Queue.Length; i++)
{
frame = FrameGenerator(frame_Queue[i]); //Generates Frames
try
{
udpClient.Send(frame, frame.Length, "192.168.4.255", 15000);
}
catch (SocketException)
{
Log.Debug("Error", "Socket Exception");
}
if(!receive.Wait(10000)) //Receive Timeout
{
RunOnUiThread(() =>
{
ShowToast("Connection Timeout. Please check device");
});
};
await Task.Delay(update_delay); //To release pressure from H/W
receive.Reset();
}
}
}
void UDP_Receive(IAsyncResult result)
{
receive.Set();
r_UdpClient = result.AsyncState as UdpClient;
data = r_UdpClient.EndReceive(result, ref sender);
RunOnUiThread(() =>
{
Update_UI(data);
});
r_UdpClient.BeginReceive(new AsyncCallback(UDP_Receive), r_UdpClient);
}
I don't know what the intent of this code is:
void InitializeUDP()
{
udpClient = new UdpClient(15001);
sender = default(IPEndPoint);
ThreadPool.QueueUserWorkItem(o => UDP_StatusCommunicator());
udpClient.EnableBroadcast = true;
udpClient.Client.ReceiveTimeout = 500;
}
but it is not guaranteed that
udpClient.EnableBroadcast = true;
udpClient.Client.ReceiveTimeout = 500;
is executed before UDP_StatusCommunicator().
For client UIs like Xamarin Task.Run can be a good option over ThreadPool.QueueUserWorkItem.
You might want to take a look at Dataflow (Task Parallel Library), in particular to the ActionBlock to replace your queue.
You might also want to consider using Progress to report updates to the UI or using Reactive Extensions (Rx) to subscribe to updates from the UI.

Instantiating the same class multiple times from threads appears as instantiated only once C# WPF

I'm developing an application in C # on WPF.
I need to launch more than once the same MyListWindow class which consists of XAML and the code behind XAML.CS.
The problem is that strange things happen (from my point of view and because of my ignorance).
In particular, I have a main thread that launches a PIPE Server which should launch multiple secondary threads, each of which instantiates a new MyListWindow window.
Strange things happen just when more than one secondary thread is launched from the main thread. First of all he throws me an exception which warns me that the MyListWindow object is already in use by another thread, but it does not make sense, because each secondary thread invokes a new one.
Part of the code is posted below:
namespace Kyactus
{
public partial class App
{
private Registration _reg = new Registration();
public App()
{
if (Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)).Count() > 1)
{
Process currentProcess = Process.GetCurrentProcess();
if (Environment.GetCommandLineArgs().Length != 2)
{
currentProcess.Kill();
return;
}
var client = new NamedPipeClientStream("IPC_Context_Menu");
client.Connect();
var writer = new StreamWriter(client);
writer.WriteLine(Environment.GetCommandLineArgs()[1]);
writer.Flush();
currentProcess.Kill();
}
else
{
Globals.MainWindow = new MainWindow();
Globals.MainWindow.Show();
StartContextMenuListener();
}
}
public void StartContextMenuListener()
{
Thread t = new Thread(myTask);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
void myTask()
{
NamedPipeServerStream server;
while (true)
{
server = new NamedPipeServerStream("IPC_Context_Menu");
server.WaitForConnection();
var reader = new StreamReader(server);
string FileOrFolderFromContextMenu = reader.ReadLine();
Thread t = new Thread(() =>
{
ListUsersContextMenu listWindow = new ListUsersContextMenu(Globals.MainWindow.UsersXAML.Items, FileOrFolderFromContextMenu);
listWindow.ShowDialog(); // Thorws: System.InvalidOperationException because object 'listWindow' is property of another thread
IList selectedUsers = listWindow.DialogResult();
foreach (User selectedUser in selectedUsers)
{
Client c = new Client();
c.invoke(selectedUser.IP.ToString(), FileOrFolderFromContextMenu, selectedUser.ID, selectedUser.Name);
}
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
t.Join();
server.Close();
}
}
}
}
How can I solve this problem? I wish I could run the lambda several times.

Broadcast from bluetooth server to multiple bluetooth clients with 32feet

I have an issue about the server-client communication.
I googled around but I did not find a solution to this.
Right now I am using 32feet in order to get in touch 2 or more (till 7) BT clients to 1 BT server.
I need to broadcast a message from the server to every device in the same time, but I don't know how to do it.
The only way I figured out was to use the list of connection in order to send the message one per time, but it means a delay between each message sent (around 100 ms per device). Unfortunately it means to have a large delay on the last one.
Can someone please give me an advice on how to solve this problem?
Is there a way to broadcast the message to all devices in the same time?
If it can be helpfull, here there is the handle of connection and reading from devices.
Thanks for your help
private void btnStartServer_Click(object sender, EventArgs e)
{
btnStartClient.Enabled = false;
ConnectAsServer();
}
private void ConnectAsServer()
{
connessioniServer = new List<BluetoothClient>();
// thread handshake
Thread bluetoothConnectionControlThread = new Thread(new ThreadStart(ServerControlThread));
bluetoothConnectionControlThread.IsBackground = true;
bluetoothConnectionControlThread.Start();
// thread connessione
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread));
bluetoothServerThread.IsBackground = true;
bluetoothServerThread.Start();
}
private void ServerControlThread()
{
while (true)
{
foreach (BluetoothClient cc in connessioniServer)
{
if (!cc.Connected)
{
connessioniServer.Remove(cc);
break;
}
}
updateConnList();
Thread.Sleep(0);
}
}
Guid mUUID = new Guid("fc5ffc49-00e3-4c8b-9cf1-6b72aad1001a");
private void ServerConnectThread()
{
updateUI("server started");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
while (true)
{
BluetoothClient conn = blueListener.AcceptBluetoothClient();
connessioniServer.Add(conn);
Thread appoggio = new Thread(new ParameterizedThreadStart(ThreadAscoltoClient));
appoggio.IsBackground = true;
appoggio.Start(conn);
updateUI(conn.RemoteMachineName+" has connected");
}
}
private void ThreadAscoltoClient(object obj)
{
BluetoothClient clientServer = (BluetoothClient)obj;
Stream streamServer = clientServer.GetStream();
streamServer.ReadTimeout=1000;
while (clientServer.Connected)
{
try
{
int bytesDaLeggere = clientServer.Available;
if (bytesDaLeggere > 0)
{
byte[] bytesLetti = new byte[bytesDaLeggere];
int byteLetti = 0;
while (bytesDaLeggere > 0)
{
int bytesDavveroLetti = streamServer.Read(bytesLetti, byteLetti, bytesDaLeggere);
bytesDaLeggere -= bytesDavveroLetti;
byteLetti += bytesDavveroLetti;
}
updateUI("message sent from "+clientServer.RemoteMachineName+": " + System.Text.Encoding.Default.GetString(bytesLetti));
}
}
catch { }
Thread.Sleep(0);
}
updateUI(clientServer.RemoteMachineName + " has gone");
}
private void updateUI(string message)
{
Func<int> del = delegate()
{
textBox1.AppendText(message + System.Environment.NewLine);
return 0;
};
Invoke(del);
}
private void updateConnList()
{
Func<int> del = delegate()
{
listaSensori.Items.Clear();
foreach (BluetoothClient d in connessioniServer)
{
listaSensori.Items.Add(d.RemoteMachineName);
}
return 0;
};
try
{
Invoke(del);
}
catch { }
}
I don't exactly understand how you do it right now (the italian names are not helping...) but maybe my solution can help you.
first of all, bluetooth classic does not support broadcast. so you have to deliver at one at a time.
i do connect to 7 serial port devices at a time, using 7 threads. then i tell every thread to send data. this is very close to same time, but of course not exactly.
let me know if that helps or if you need a code example.

Windows Service: The calling thread cannot access this object because a different thread owns it

Trying to convert XML files using XSL and printing the output. However, receiving the following message: The calling thread cannot access this object because a different thread owns it.
To set an interval for checking files, added a timer to the OnStart.
if (findPrinter() > 0)
{
System.Timers.Timer printNetterCheck = new System.Timers.Timer();
printNetterCheck.Elapsed += new ElapsedEventHandler(OnTimedEvent);
printNetterCheck.Interval = 30000;
printNetterCheck.Enabled = true;
}
The OnTimedEvent:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
getFiles();
}
If any files available, call print:
foreach (string file in files)
{
try
{
StringWriter xslTransformResult = new StringWriter();
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslPath);
xslt.Transform(file, null, xslTransformResult);
if (print(xslTransformResult) == 1)
{
//do some things
The print function:
private int print(StringWriter transformedXML)
{
//assume OK
int rc = 1;
try
{
StringReader printNetterStreamReader = new StringReader(transformedXML.ToString());
PrintSystemJobInfo printNetterJob = printer.AddJob("PrintNetterPrint");
Stream printNetterStream = printNetterJob.JobStream;
Byte[] printNetterByteBuffer = UnicodeEncoding.Unicode.GetBytes(printNetterStreamReader.ReadToEnd());
printNetterStream.Write(printNetterByteBuffer, 0, printNetterByteBuffer.Length);
printNetterStream.Close();
}
catch (Exception e)
{
//return fail
rc = -1;
eventLog.WriteEntry("Error printing: " + e.Message, EventLogEntryType.Error);
}
return rc;
}
When calling print I receive the thread error. Found some stuff about Dispatchers etc.. but those are not available when using services.
Check PrintQueue.AddJob.
The method makes a COM call which requires the application be running in a single apartment (STA). The easiest way to fix that is to add STAThreadAttribute to Main which will force the application to run in a single thread. If you need multithreading in your application then you will need to implement the necessary plumbing to run the PrintQueue separately on an STA Thread.
// Create a factory to hold your printer configuration
// So that it can be retrieved on demand
// You might need to move the findPrinter() logic
public class PrintQueueFactory
{
private static PrintQueue _instance = new PrinterQueue(/* Details */);
public static PrintQueue PrintQueue { get { return _instance; } }
}
private int print(StringWriter transformedXML)
{
//assume OK
int rc = 1;
try
{
var printer = PrintQueueFactory.PrintQueue;
var staThread = new Thread(() => Print(printer, transformedXML.ToString()));
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
}
catch (Exception e)
{
//return fail
rc = -1;
eventLog.WriteEntry("Error printing: " + e.Message, EventLogEntryType.Error);
}
return rc;
}
private static void Print(PrintQueue printer, string lines)
{
using(var printNetterJob = printer.AddJob("PrintNetterPrint"))
using(var printNetterStreamReader = new StringReader(lines))
using(var printNetterStream = printNetterJob.JobStream)
{
Byte[] printNetterByteBuffer = UnicodeEncoding.Unicode.GetBytes(printNetterStreamReader.ReadToEnd());
printNetterStream.Write(printNetterByteBuffer, 0, printNetterByteBuffer.Length);
}
}
maybe, as you are using a Timer control, it is related with multi-threading, maybe you should check if an Invoke is Required (InvokeRequired) in the Timer.Elapsed event handler.
If so, you should create a delegate to call this function, so it can be executed in the right thread.
Check this Invoke-Required question

Background Worker Thread Problem

I am using background worker in my Application
my code for this
void CreateThreadForEachServer()
{
DataAccess oDA = new DataAccess();
List<Server> allServerData = oDA.GetAllServers();
foreach (Server serverData in allServerData)
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerAsync(serverData);
}
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Server server = (Server)e.Argument;
CreateSnapshotForEachServer(server);
}
void CreateSnapshotForEachServer(Server server)
{
DataAccess oDA = new DataAccess();
MsmqMessageFormat message = new MsmqMessageFormat();
try
{
message = new Queue().ReadMessageFromMSMQ(server.ServerName);
}
catch
{
}
}
My problem is when I am calling this method
try
{
message = new Queue().ReadMessageFromMSMQ(server.ServerName);
}
catch
{
}
in a background worker then i can not able to call this method just read a message from MSMQ
But when i can't use background worker just call this method in simple thread like this
void CreateThreadForEachServer()
{
DataAccess oDA = new DataAccess();
List<Server> allServerData = oDA.GetAllServers();
foreach (Server serverData in allServerData)
{
ThreadStart t = delegate { CreateSnapshotForEachServer(serverData); };
Thread td = new Thread(t);
td.Priority = ThreadPriority.Highest;
td.Start();
}
}
then this method call properly
try
{
message = new Queue().ReadMessageFromMSMQ(server.ServerName);
}
catch
{
}
what is the problem with background worker my Queue class is like this
class Queue
{
public MsmqMessageFormat ReadMessageFromMSMQ(string queueName)
{
MessageQueue messageQueue = null;
messageQueue = new MessageQueue(#".\Private$\" + queueName);
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(MsmqMessageFormat) });
System.Messaging.Message msg = null;
System.Messaging.Message[] allMessages = messageQueue.GetAllMessages();
if (allMessages.Length > 0)
{
msg = messageQueue.Receive();
MsmqMessageFormat readMessage = (MsmqMessageFormat)(msg.Body);
return readMessage;
}
else
{
return null;
}
}
}
and MsmqMessageFormat class is like this
[Serializable]
public class MsmqMessageFormat
{
public Zvol Zvol { get; set;}
public List<PolicyInterval> listPolicyIntervalInfo = new List<PolicyInterval>();
}
Can you clarify on the context of your application?
Is it a Windows Forms app? Console app? Or WPF?
It could have something to do with the apartmentstate of the thread. Threads used by the BackgroundWorker are defaulted to MTA (and you can't override it). While threads created manually could have there apartmentstate set to STA.
I'm not sure about your approach is correct.. I would read messages one by one and bind the appropriate events.
From the link:
The Message Loop
The final line in the example above
was "queue.BeginReceive()". This is a
critical line to a successful
implementation of Microsoft Message
Queue in that it provides the means
for continuous listening on the
message queue. Each time a message is
received, the listening process stops.
This helps provide a thread-safe
environment. However, it also means
it's the developer's responsibility to
resume listening to the queue.
Using the Microsoft Message Queue MSMQ and C#
Also in the last bit of code you have in your question:
if (allMessages.Length > 0)
{
msg = messageQueue.Receive();
MsmqMessageFormat readMessage = (MsmqMessageFormat)(msg.Body);
return readMessage;
}
else
{
return null;
}
This will get all messages and consume them, but will only return the first message even if there are more than one in the queue.

Categories

Resources