I am trying to connect to wifi with the following code:
private static bool ConnectToWifi(string profileName, WlanClient.WlanInterface wlanIface, Wifi wifi, string profile)
{
try
{
wlanIface.SetProfile(Wlan.WlanProfileFlags.AllUser, profile, true);
}
catch (Exception e)
{
var ex = e;
return false;
};
// Task.Run()
wlanIface.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Infrastructure, profileName);
Thread.Sleep(5000);
var status = wifi.ConnectionStatus;
var x = wlanIface.GetProfileXml(profileName);
if (status == WifiStatus.Disconnected)
{
return false;
}
return true;
}
I have kept a delay of 5000 ms to ensure the network is connected, but this is causing my UI to not show the loading icon when this code executes.
How I can make my UI also update at same time, instead of waiting for the connection?
You have two options:
(Both of which make it not possible to return a bool that indicates a successful connection without a bit more logic around it.)
Move your code to a separate thread (if the rest of it is thread-safe) and use the synchronous methods instead:
private static void ConnectToWifi(string profileName, WlanClient.WlanInterface wlanIface, Wifi wifi, string profile)
{
new Thread(()=>{
bool result = false;
try
{
wlanIface.SetProfile(Wlan.WlanProfileFlags.AllUser, profile, true);
wlanIface.ConnectSynchronously(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Infrastructure, profileName, 5000);
var status = wifi.ConnectionStatus;
var x = wlanIface.GetProfileXml(profileName);
result = (status != WifiStatus.Disconnected);
}
catch (Exception e)
{
var ex = e;
}
finally
{
Dispatcher.BeginInvoke(new Action(()=>{WhateverYouDoWithYourResult(result);}));
}
}).Start();
}
Or subscribe to the WlanConnectionNotification (Not being able to connect might not be seen as a change, so you have to test that):
private static bool ConnectToWifi(string profileName, WlanClient.WlanInterface wlanIface, Wifi wifi, string profile)
{
try
{
wlanIface.WlanConnectionNotification += Interface_ConnectionStateChanged;
wlanIface.SetProfile(Wlan.WlanProfileFlags.AllUser, profile, true);
wlanIface.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Infrastructure, profileName);
return true; //Just means the attempt was successful, not the connecting itself
}
catch (Exception e)
{
var ex = e;
return false;
}
}
private static void Interface_ConnectionStateChanged(Wlan.WlanNotificationData notifyData, Wlan.WlanConnectionNotificationData connNotifyData)
{
// Do something with that info, be careful - might not be the same thread as before.
}
I don't have access to a Wifi right now, so I haven't tested above code. It should work, but you better consider it pseudo-code instead of an actual ready-to-use solution.
Whenever you execute Thread.Sleep in the UI thread, you interrupt processing all UI messages, which makes your UI unresponsive. Hence, Thread.Sleep and any other long running operations should never be executed in the UI thread.
The solution is to execute these operations in a separate thread to allow the UI thread to continue UI operations. It is generally a good idea to let the UI thread do only UI operations.
In your case it means that the caller should execute the operation in a task:
private static bool ConnectToWifi(string profileName, WlanClient.WlanInterface wlanIface,
Wifi wifi, string profile, Action<bool> resultCallback, Dispatcher dispatcher)
{
//Your connect code
bool result;
if (status == WifiStatus.Disconnected)
{
result = false;
}
else
{
result = true;
}
dispatcher.BeginInvoke(() => resultCallback(result));
return result;
}
Another thing: Thread.Sleep is not a good idea in task, since you don't know which scheduler you are running on. You should use Task.Delay instead. In this case Thread.Sleep is generally not a good idea, since you just wait and hope your task is done in five seconds, which is not guaranteed. Also you might simply waste 5 seconds of the user's time in case it connects immediately. The better solution is to use a wait loop and check regularly if the connection is established. If you expect the connection to happen in rather short time, you can use SpinWait.SpinUntil (with a timeout of five seconds):
SpinWait.SpinUntil(() => wifi.ConnectionStatus == WifiStatus.Connected, 5000);
Related
I have a TCP reconnect method in a winforms application; multiple threads try to send/receive data over TCP. If the connection is lost while sending the data reconnection is called (can be called from multiple threads). However, I don't want to execute the reconnect multiple times.
To achieve this, I'm using the below code- please let me know if this is a good way.
Thanks in advance.
public bool Reconnect(out bool wasLockedByOThers)
{
bool reconnected = wasLockedByOThers = false;
try
{
//check if the lock can be acquired immediately
if (!Monitor.TryEnter(m_ReconnectLock))
{
// if not, wait until the lock is acquired. If the lock is acquired here it means reconnect just happened so I'll just return without running it again. But the problem is I'll not know if the previous reconnect call resulted in true or false.
Monitor.Enter(m_ReconnectLock);
wasLockedByOThers = true;
}
else
{
reconnected = true; //reconnect logic
}
}
catch (Exception ex)
{
reconnected = false;
}
finally
{
Monitor.Exit(m_ReconnectLock);
}
return reconnected;
}
So my issue here is simple. I've designed a WinForms application and it works well on my machine (Win7), and in fact other machines, yet when I run the application on a Windows 10 2016 LTSB machine, my background threads do not work as expected - yet some do perform as expected.
Application flow:
Wait 1 minute (obj1 with Threading.Timer)
Post event (a string message from obj1 when MainWindow calls obj1)
Update form text (with info from event message)
Perform operation (background thread)
Post event message (from background thread to MainWindow)
Wait random period (obj1 with Threading.Timer)
Post event (a string message from obj1)
Update form
Wait 1 minute
Now for some privacy policies/reasons I cannot share the exact things that operate here and how the classes are structured, but here is a rudimentary class structure:
class MainWindow
{
List<Controller> controllers = new List<Controller>();
List<ControllerDisplay> controllerDisplays = new List<ControllerDisplay>();
Queue<string> requests = new Queue<string>();
private void AppLifetimeLoopCallback(object state)
{
while (requests.Count > 0)
{
string request = requests.Dequeue();
string response = controllers[i].ProcessRequest(request);
string anotherResponse = controllerDisplays[i].ProcessResponse(response);
if (!string.NullOrWhiteSpace(anotherResponse))
{
requests.Enqueue(anotherResponse);
}
}
for (int i = 0; i < controllers.Count; i++)
{
requests.Enqueue("STATE?");
}
timer.Change(300, Threading.Timeout.Infinite);
}
}
class Controller
{
public string ProcessRequest(string request)
{
switch (request)
{
case "STATE?":
if (shouldRequest)
{
return "REQ:1234";
}
else if (isProcessing)
{
return "PRQ:1234";
}
else
{
return "IDLE";
}
break;
case "APPROVE":
shouldRequest = false;
isProcessing = true;
thread = new Threading.Thread(new ThreadStart(() =>
{
Threading.Thread.Sleep(300);
isProcessing = false;
return "RQF:1234";
})
{
IsBackground = true,
};
thread.Start();
break;
case "DENY:
shouldRequest = false;
break;
}
}
}
class ControllerDisplay
{
public string ProcessResponse(string response)
{
switch (request.Substring(0, 4))
{
case "REQ:":
thread = new Threading.Thread(new ThreadStart(() =>
{
// perform some checks
if (isValid)
{
return "APPROVE";
}
else
{
return "DENY";
}
})
{
IsBackground = true,
};
thread.Start();
break;
case "RQF:":
thread = new Threading.Thread(new ThreadStart(() =>
{
// finalize and cleanup request bits
return "APPROVE";
})
{
IsBackground = true,
};
thread.Start();
break;
case "PRQ:":
// update UI
break;
}
}
}
Now firstly, I know there seems to be some discrepancy between the millisecond delay in the code and the description of the flow - however note that there is another Thread in the Controller which toggles the shouldRequest value at this minute interval which switches up the response messages to perform the "request" when the device's state is requested.
Secondly I also have registered to the UnhandledException as well as the ThreadException events of the application which should log any undesired behaviour that occurred.
Third, note that in MainWindow there is a Threading.Timer (not in code - I know) that is updating the UI with the current date and time every second.
Now the issue here that I've noticed is that on the Win10LTSB2016 machine, the application stops performing the background operations. Some of the threads must have just died off or something as i.e. the date and time keeps updating as expected, but one controller will be stuck in request state and another in a request complete state - and no error messages logged / MessageBox. Note that the machine does not go into any sleep or hibernate state in this period that the threads just stop, and another note is that the memory sockets is 1, not 2 (as I read that this could affect the threads losing communication with each other if they are compartmentalized to different processor groups and your application is not written to handle this).
Closing off:
Note that when I perform checks to see if I should i.e. start the request process thread in the Controller class so as to not do the same request over and over until state change is detected, I do the following:
lock (checkLock)
{
if (isProcessingRequest)
{
break;
}
else
{
lock (resourceLock)
{
isProcessingRequest = true;
}
}
}
thread = new Threading.Thread(new ThreadStart(() =>
{
lock (resourceLock)
{
// finalize and cleanup request bits
isProcessingRequest = false;
}
return "APPROVE";
})
{
IsBackground = true,
};
thread.Start();
I'm closing this question as it is complete hogwash and I apologize to those for the time they spent reading this.
So the manual locks on the Queue<T> kept causing a deadlock before, thus they were removed. Now it seemed to resolve the issue at first, but long running tests proved every now and again (what I thought was a Windows issue) a deadlock occurred.
The reason I had thought this was a Windows issue is because someone telling me that this is what they experienced on Windows and it is definitely a Windows issue. Not looking down on anyone, but he does not do threading as he does not know how and the mentioned result was from his attempt to do threading. Lesson learned here.
Thanks guys and/or gals.
EDIT:
The issue was resolved and long running tests are looking very promising thus far. To achieve this, I simply changed Queue<T> to ConcurrentQueue<T> and a few modifications to code where needed (i.e. ConcurrentQueue<T>.Clear() does not exist where Queue<T>.Clear() does).
With the help of Google and community, I was able to build a nice set of methods allowing me to asynchronously call a function. This function is testing remote host properties, so it is idling most of the time. For this reason I would like to maximize the number of concurrent threads launched such that all calls can be processed in the minimum amount of time.
Here is the Code I have so far:
// Check remote host connectivity
public static class CheckRemoteHost
{
// Private Class members
private static bool AllDone = false;
private static object lockObj = new object();
private static List<string> IPs;
// Wrapper: manage async method <Ping>
public static List<string> Ping(HashSet<string> IP_Ports, int TimeoutInMS = 100)
{// async worker method: check remote host via <Ping>
// Locals
IPs = new List<string>();
// Perform remote host check
AllDone = false;
Ping_check(IP_Ports, TimeoutInMS);
while (!AllDone) { CommonLib.Utils.ApplicationWait(10, 10); }
// Finish
return IPs;
}
private static async void Ping_check(HashSet<string> IP_Ports, int timeout)
{
// Locals
var tasks = new List<Task>();
// Build task-set for parallel Ping checks
foreach (string host in IP_Ports)
{
var task = PingAndUpdateAsync(host, timeout);
tasks.Add(task);
}
// Start execution queue
await Task.WhenAll(tasks).ContinueWith(t =>
{
AllDone = true;
});
}
private static async Task PingAndUpdateAsync(string ip, int timeout)
{
// Locals
System.Net.NetworkInformation.Ping ping;
System.Net.NetworkInformation.PingReply reply;
try
{
ping = new System.Net.NetworkInformation.Ping();
reply = await ping.SendPingAsync(ip, timeout);
if(reply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
lock (lockObj)
{
IPs.Add(ip);
}
}
}
catch
{
// do nothing
}
}
}// end public static class CheckRemoteHost
This code is tested quite extensively, and the code seems stable and reliably report live hosts. Having said that, I know that it only spawns 8 threads at a time (= number of logical core on my test machine).
The key portion of the code is this:
// Start execution queue
await Task.WhenAll(tasks).ContinueWith(t =>
{
AllDone = true;
});
This is where I would like to increase/ maximize the number of concurrently launched threads to something like 25 per core (remember the thread job is 99% idle).
So far, my thread concurrency research has brought up the explicit thread and Parallel.For approaches. However, these seem to have the same shortcoming of spawning no more than 8 threads.
Any help would be very much appreciated, so thank you very much in advance everyone for looking!
You're making your life hard with the code you have. It's got a lot of plumbing that isn't needed and you're sharing static fields that would cause your code to fail if you called Ping a second time while the first one is running.
You need to get rid of all of that stuff.
I'd suggest using Microsoft's Reactive Framework - just NuGet "System.Reactive" and add using System.Reactive.Linq; to your code. Then you can do this:
public static class CheckRemoteHost
{
public static IList<string> Ping(HashSet<string> IP_Ports, int TimeoutInMS = 100)
{
var query =
from host in IP_Ports.ToObservable()
from status in Observable.FromAsync(() => PingAsync(host, TimeoutInMS))
where status
select host;
return query.ToList().Wait();
}
private static async Task<bool> PingAsync(string ip, int timeout)
{
try
{
var ping = new System.Net.NetworkInformation.Ping();
var reply = await ping.SendPingAsync(ip, timeout);
return reply.Status == System.Net.NetworkInformation.IPStatus.Success;
}
catch
{
return false;
}
}
}
That's it. That's all of the code you need. It's automatically maximising the thread use to get the job done.
I am working on an application that talks to a motion controller over ethernet.
To connect to the controller I use a library provided by the supplier, to connect you create an instance of the controller than then tell it to connect, this has the chance to block for a few seconds (with no controllable timeout) if there is no controller present. This cause freeze ups in the UI.
To avoid this I thought I would be able to use Tasks to run the connection in a different thread.
ConnectionTask = Task.Factory.StartNew(() =>
{
try
{
RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
RMC.Connect();
}
catch
{
this.logger.Log("Failed to connect");
}
}, TaskCreationOptions.LongRunning);
This has no effect whatsoever and the UI still locks up.
I think I am using them properly as if I replace it with the below code the UI is fine even though the separate thread takes a few seconds before the message comes out.
ConnectionTask = Task.Factory.StartNew(() =>
{
int x = 1;
while (x != 0) x++;
this.logger.Log("Failed to connect");
}, TaskCreationOptions.LongRunning);
Is there any way I can identify what is going on and prevent calls that I do not know anything about their inner workings from locking the UI thread.
Use async/await, something along the lines of:
public async void MyButton_Click(object sender, EventArgs e)
{
await CreateEthernetLink();
this.logger.Log("Connected!");
}
private async Task CreateEthernetLink()
{
var task = Task.Run(() => {
try
{
RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
rmc.Connect();
}
catch
{
this.logger.Log("Failed to connect");
}});
await task;
}
The await will capture the current thread (or SynchronizationContext - in this case the UI thread which is being blocked) and restore it after the async work has been completed.
So the threading is all handled for you behind the scenes and you should notice no difference in your application other than the fact that your application no longer freezes when performing connections.
EDIT: I also noticed in your code your initializing rmc but calling connect on RMC. I don't think this is correct.
In short, I want to display a progress indicator, make a REST service call, and hide the indicator.
My progress indicator is bound to a property which when set to true or false, show or hides it. My indicator is a little spinning wheel and I obviously don't want my UI to hang when I make a the web service call, so this is done by calling an Async function.
I found some code earlier on which works great to achieve what I want to do, however there is a but!
Here is the simplified version code I'm using:
try
{
ThreadPool.QueueUserWorkItem(async data =>
{
var dispatcher = Deployment.Current.Dispatcher;
dispatcher.BeginInvoke(() =>
{
this.IsRunning = true;
});
configModel = LoginUser(loginId, password);
dispatcher.BeginInvoke(() =>
{
this.IsRunning = false;
});
});
}
catch (Exception ex)
{
IDialogService dialogService = this.GetService<IDialogService>();
dialogService.Show("Unhandled Exception", ex.Message);
dialogService = null;
}
The problem occurs when my web service fails for whatever reason i.e. blocked by firewall for example. Even though I have a try catch, it doesn't get caught and crashes my app.
Is there another way to achieve this without using the threadpool? What's the cleanest way to achieve this?
I really need to call the this.IsRunning as this looks after showing and hiding my progress indicator but this obviously needs to be running on the UI thread, while the rest call needs to be running on another thread.
You need to try/catch the actual service call, not the QueueUserWorkItem:
try
{
configModel = LoginUser(loginId, password);
}
catch (...)
{
}
dispatcher.BeginInvoke(() =>
{
this.IsRunning = false;
});
Otherwise, your IsRunning = false will never execute.
However
If you want the cleanest way, then you make LoginUser asynchronous so you can await it.
this.IsRunning = true;
try
{
configModel = await LoginUser(loginId, password);
}
catch (...)
{
// report error here
}
this.IsRunning = false;