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).
Related
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);
I'm using threads to connect to multiple clients (PLCs) from my program. Program will send data and receive response from the PLC(s).. The problem im having is, when in debugging mode, (toggle breakpoint) one step at a time..the program work pretty much ok!, with the ID received confirming that it's coming from one of the thread.. but if I just debug without toggling any breakpoint, the response event will receive the same ID, although on different thread.. what could be wrong...
Debugging mode with breakpoint:
Debugging mode without breakpoint:
Below is my code
Start Request:
private void StartRequest()
{
foreach (ModbusTCP work in works)
{
work.Connect();
Thread.Sleep(1000);
if (work.Connected)
{
try
{
Thread thread = new Thread(new ThreadStart(() => work.StartReadHoldingRegister())) {
Name = ((ReadHoldingRegisterParam)work.SetReadHoldingRegisterParam).id.ToString(),
IsBackground = true
};
work.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent);
work.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);
thread.Start();
threads.Add(thread);
}
catch (ThreadStateException ex)
{
MessageBox.Show(ex.Message);
}
}
else
work.Disconnect();
}
}
Response Event
private void modbus_OnResponseEvent(object sender, ModbusTCP.ResponseEventArgs e)
{
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
AddRow(RcvDataGrid, new PLCPacket() {
PLCId = e.id.ToString(),
PLCIp = "Test",
PLCTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt"),
PLCData = ""
});
}));
}
}
}
Your variable work is shared among the threads. Once a thread is executed it takes whatever value your variable work has. That depends how quick each thread is processed. When you step through your code with a debugger you don't experience that.
If you capture the value before the anonymous method you should be fine:
try
{
// capture the current value of the loop variable
ModbusTCP localWork = work;
// so the anonymous method uses the reference in localWork
// instead of whatever value work has, which can be anywhere
// the future, worst case after your loop is finished, where
// work would hold the last value of the loop, and then
// start all threads with that value.
Thread thread = new Thread(
new ThreadStart(
() => localWork.StartReadHoldingRegister()))
{
Name = ((ReadHoldingRegisterParam) localWork.SetReadHoldingRegisterParam).id.ToString(),
IsBackground = true };
});
localWork.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent);
localWork.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);
A side comment:
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
This code is very unlikely to be correct. Here you are obtaining a lock in the original thread and then submitting a new action, async. The lock is scoped to the current method, and thus will be released as soon as the BeginInvoke call returns, not during the action itself. The only operations actually guarded by the lock is the e.data.Length check, which operates on a parameter (not shared) state and thus does not need protection.
It would make more sense to place the lock inside the action, but the action is always executed on the main thread and thus is unlikely to actually need protection (because is, basically, single threaded). Is difficult to guess exactly what you're trying to achieve w/o seeing the whole code, but that lock(lockingObject) is very unlikely to be necessary, or useful.
To clarify on my question I've been developing an app that does a lot of database updates / web service calls based on the input from a user (using an excel spreadsheet). If there are a lot of updates to make the process can take in excess of 20 minutes to run.
To stop my UI from freezing / timing out I've been looking into multithreading so I can run my long running process in an asynchronous manner and in the mean time simply displaying an animated gif whilst the process runs.
This all seems to run nicely at the moment with my test data, but when I substitute in the actual long running process I get an error regarding HttpContext.Current.User.Identity.Name. I've read up on this and from this article1 I took it to mean that if you set the 'Async' property to 'true' in the page directive and used the RegisterAsyncTask method you could then access HttpContext.Current. However, for me this doesn't seem to be true. I'm sure it's something I'm doing, so here is my code (I've mainly been using the following articles to write this article2 and article3):
ASP.NET page
<%# Page Title="Home Page" Async="true" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Index.aspx.cs" Inherits="MyApp.Index" %>
C# - RegisterAsyncTask is done on a button click, which starts the long running process:
protected void ProcessUpdates()
{
//Register async task to allow the processing of valid updates to occurr in the background
PageAsyncTask task = new PageAsyncTask(OnBegin, OnEnd, OnTimeOut, null);
RegisterAsyncTask(task);
}
IAsyncResult OnBegin(Object sender, EventArgs e, AsyncCallback cb, object state)
{
return Worker.BeginWork(cb, state);
}
private void OnEnd(IAsyncResult asyncResult)
{
//UpdateResults list should now have been filled and can be used to fill the datagrid
dgProcessedUpdates.DataSource = Worker.UpdateResults;
dgProcessedUpdates.CurrentPageIndex = 0;
dgProcessedUpdates.DataBind();
lblProgress.Text = "Update Results: update success / failure is shown below";
}
private void OnTimeOut(IAsyncResult asyncResult)
{
lblProgress.Text = "The process has timed out. Please check if any of the updates have been processed.";
}
C# - Worker class
public class Worker
{
public static List<AuditResult> UpdateResults = new List<AuditResult>();
private delegate void del();
//This method is called when the thread is started
public static IAsyncResult BeginWork(AsyncCallback cb, object state)
{
del processing = DoUpdateProcessing;
return processing.BeginInvoke(cb, state);
}
private static void DoUpdateProcessing()
{
//UpdateResults = ExcelFileProcessing.PassValidUpdates();
//Testing
Thread.Sleep(5000);
int i = 0;
while(i < 10)
{
AuditResult ar = new AuditResult();
ar.Result = "Successful";
ar.JobNumber = (1000 + i).ToString();
ar.NewValue = "Test New Value " + i.ToString();
ar.ResultDate = DateTime.Now.ToString();
ar.UserName = HttpContext.Current.User.Identity.Name;
UpdateResults.Add(ar);
i++;
}
}
}
Initially my test code didn't include a call to HttpContext.Current.User.Name for ar.UserName but after my issues with putting back in the call to ExcelFileProcessing.PassValidUpdates() with this I decided to do it. When I reach that part (ar.UserName = HttpContext.Current.User.Identity.Name) it says 'Object reference not set to an instance of an object', which suggests the HttpContext isn't carried across to the second thread. How can I do this?
UPDATE
I've currently reverted back to my previous code (that wasn't initially working) and simply passed the HttpContext.Current as a variable to my DoWork method as per this SO question like this:
Create 2nd thread
protected void ProcessValidUpdates()
{
Worker workerObject = new Worker();
HttpContext ctx = HttpContext.Current;
Thread workerThread = new Thread(new ThreadStart(() =>
{
HttpContext.Current = ctx;
workerObject.DoWork();
}));
workerThread.Start();
//Loop until worker thread activates
while (!workerThread.IsAlive) ;
//Put main thread to sleep to allow the worker thread to do some work
Thread.Sleep(1000);
//Request the worker thread stop itself
workerObject.RequestStop();
//Use the Join method to block the current thread until the object's thread terminates
workerThread.Join();
//UpdateResults list should now have been filled and can be used to fill the datagrid
dgProcessedUpdates.DataSource = Worker.UpdateResults;
dgProcessedUpdates.CurrentPageIndex = 0;
dgProcessedUpdates.DataBind();
lblProgress.Text = "Update Results: update success / failure is shown below";
}
Worker Class
public class Worker
{
//volatile hints to the compiler that this data member will be accessed by multiple threads.
private volatile bool _shouldStop;
public static List<AuditResult> UpdateResults = new List<AuditResult>();
//This method is called when the thread is started
public void DoWork()
{
while (!_shouldStop)
{
//Testing
Thread.Sleep(5000);
int i = 0;
while (i < 10)
{
AuditResult ar = new AuditResult();
ar.Result = "Successful";
ar.JobNumber = (1000 + i).ToString();
ar.NewValue = "Test New Value " + i.ToString();
ar.ResultDate = DateTime.Now.ToString();
ar.UserName = HttpContext.Current.User.Identity.Name;
UpdateResults.Add(ar);
i++;
}
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
This seems to work in that I can now access HttpContext.Current and the username I expect. I think this is probably to some degree what some of you were proposing anyway. I appreciate the solution suggested by Andrew Morton but at the moment that would require a significant rewrite. At the moment my process already calls a web service to do the database stuff and returns a success or failure result. It also has to call another BPEL service directly. As such I suspect there may be further performance hits if I had to wrap all this into another web service. In addition, most calls to the process won't be that long running (probably less than 10 mins), so this is really only to address the few requests that exceed 20 mins. Finally, this is only likely to be used by 1 or 2 people, so it's unlikely to have a huge number of requests at 1 time.
However, bearing in mind my current solution, is there anything I should be aware of that might trip me up? IIS causing issues? Any additional help would be very much appreciated.
I have a site on a shared server. I need to have a BATCH job and I do that in another thread. It can run up to 1 hour (I ping the site so the worker process does not stop).
I went down the road of tying to get the current context. After many hours of research and searching it cannot be done. In a new thread the httpcontent.current is not there, it is not the same thread as the user was accessing, so the context did not carry over, and you cannot access the logged in user, since they are not logged into that thread.
I have a method that occasionally hangs (in a dll I cannot modify but must use). If I run it again It will typically work fine. I was wondering if it would be possible to make a background thread that would wait for 20 minutes and then throw an exception in my program.
var triesLeft = 5;
while (triesLeft > 0) {
try {
var t = new Thread(() => { wait(20 minutes); throw new ApplicationHungException();})
t.Start();
Object o = MethodThatHangsForever10PercentOfTheTime();
} catch (ApplicationHungException e) {
triesLeft--;
}
}
t.Abort();
This does not work because the exception does not pass to the try catch block it's contained in. Is there a way I can get the thread to give it's exception to the try catch block?
One way to do this would be set off your faulty method in the separate thread, and wait for one of two things to happen; either:
The thread completes, or
A predetermined amount of time (eg 20 mins) elapses
Once either of these things happens, we can take appropriate action.
The code would look something like this:
static void DoProcessing() {
var triesLeft = 5;
Object o = null;
while (triesLeft > 0) {
var t = new Thread(() => { o = MethodThatHangsForever10%OfTheTime(); }).Start();
if (t.Join(new TimeSpan(0, 20, 0))) {
// The thread completed
break;
} else {
// We're out of time.
t.Abort(); // Important: See comments below about this
triesLeft--;
}
}
}
It turns out that aborting threads is a risky and fragile operation, as pointed out by Reed Copsey in the comments below. Your alternatives are to allow the hung thread to live out the rest of its life (however long that may be), or to quarantine the Heisenbuggy method call to a separate process.
This opens up another can of worms however, since you would have to deal with interprocess communication, data serialization and synchronisation. This may or may not be worth it, which is a judgement call I leave to you.
You can do your work in a separate thread, and wait 20 minutes for it to complete:
var triesLeft = 5;
while (triesLeft > 0)
{
var mre = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(_ => {
MethodThatHangsForever10PercentOfTheTime();
mre.Set();
});
if (mre.WaitOne(TimeSpan.FromMinutes(20)))
{
break; // Success!
}
triesLeft--;
}
}
I'm not to sure about something about EventWaitHandle.Set.
When called from within current thread and there is another thread waiting for the event, do the current thread get to sleep so that other thread gets to run (ASAP)?
I'm asking because in some of my code I have to add some object to a "threads shared" queue and that operation has really to go as quick as possible. But in the other thread where that queue is being used, speed is "not required".
So I'm proceeding like this:
// Speed "not required"
mailThread = new Task(() =>
{
for (; ; )
{
MailMessage mail;
pushMailLockMREvt.WaitOne();
{
if (mails.Count == 0)
{
mail = null;
}
else
{
mail = mails.Dequeue();
}
}
pushMailLockMREvt.Set(); // Does this put current on sleep on lower it's priority??
if (mail != null)
{
try
{
MailClient.Send(mail);
}
catch (Exception exe)
{
}
}
else
{
mailSem.WaitOne();
}
}
});
[...]
// Speed required
var task = new Task(() =>
{
pushMailLockMREvt.WaitOne(); // ASAP please...
{
mails.Enqueue(mailMessage);
if (mails.Count == 1)
{
mailSem.Set();
}
}
pushMailLockMREvt.Set();
});
No, the current thread will not sleep just because it signals the wait handle. But it may relinquish the rest of its timeslice (that's pretty subtle and low-level and isn't something you should rely on). You should not need to take any special action.
It is probably the case that the thread that has just finished waiting will get a brief boost in thread priority.
See this documentation for the Windows API function SetThreadPriorityBoost() from which I quote:
When a thread is running in one of the dynamic priority classes, the system temporarily boosts the thread's priority when it is taken out of a wait state.
Also see this documentation.
So the thread that just woke up from the wait should (normally) get a small boost. I'm not totally sure that this also applies to managed threads, but I seem to remember reading somewhere that it does. I can't find the source of that, though.