In a simple form app I'm running a constant thread when the app starts. Upon its first iteration everything goes smoothly and the thread method "Thread_ContinousChecker" works as intended. After it's run once and the the lockChecker.returnBlock() == true hits then it does not run again. Ie, does not attempt again. I have a hunch that it is something to do with the await lockChecker.checkTime() line but don't understand why, if it works once why would it stop?
Note : It only stops working if the first if statement in the Thread_ContinousChecker method hits, ie if lockChecker.returnBlock() method is true. If it's false, it continues on.
Here is my program class
static class Program
{
//Instantiate the lockform
static LockForm lockForm;
public static bool checkLockForm()
{
Form checker = Application.OpenForms["LockForm"];
return (checker == null);
}
public static void toggleLockForm(bool theBool)
{
//If theBool (our condition) is true start the form
if (theBool == true)
{
//Checks if form already eixsts
if (checkLockForm() == true)
{
//Starts the form
Application.Run(lockForm = new LockForm());
}
}
//Now if theBool is false - we want to close down any instances of the form that we may have started
if (theBool == false)
{
//This is saying if an instance of a LockForm exists
if (checkLockForm() == false)
{
//Rest of app does not close but that lockform is disabled.
//lockForm.Close();
Application.Restart();
}
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
MyController cont = new MyController();
//Start new thread for our lock checking
Thread thread = new Thread(new ThreadStart(cont.Thread_ContinuousChecker));
thread.IsBackground = true;
thread.Name = "Data Polling Thread";
thread.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TrayApp());
}
public class MyController
{
public Boolean checkForm()
{
if (Process.GetProcessesByName("ControlApp.exe").Length > 0)
{
// Is running
return true;
}
if (Process.GetProcessesByName("ControlApp.exe").Length == 0)
{
// Is not running - so start it
return false;
}
return false;
}
public async void Thread_ContinuousChecker()
{
while (true)
{
if (checkForm() == false)
{
LockLogic lockChecker = new LockLogic();
await lockChecker.checkTime();
if (lockChecker.returnBlock() == true)
{
Program.toggleLockForm(true);
}
if (lockChecker.returnBlock() == false)
{
Program.toggleLockForm(false);
}
}
Thread.Sleep(10000);
}
}
}
Here is my LockLogic's .checkTime() method which I'm awaiting in the above Program class
public async Task checkTime()
{
// Read values back from Json file
var serializedList = await Task.Run(() => File.ReadAllText(_filePathTimes));
// getting a list of LockTime objects
var lockTimeList = await Task.Run(() => (List<LockTime>)JsonConvert.DeserializeObject(serializedList, typeof(List<LockTime>), new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error }));
//
if (lockTimeList == null)
{
return;
}
if(lockTimeList.Count == 0)
{
return;
}
_lockTimes = lockTimeList;
//Then I do a foreach loop to go through every value in the start list and add the same located value to my listOfTimes (the list of LockTime objects with start and end)
for (int x = 0; x < _lockTimes.Count; x++)
{
TimeSpan start = new TimeSpan(_lockTimes[x].Start.Hour, _lockTimes[x].Start.Minute, _lockTimes[x].Start.Second);
TimeSpan end = new TimeSpan(_lockTimes[x].End.Hour, _lockTimes[x].End.Minute, _lockTimes[x].End.Second);
TimeSpan now = new TimeSpan(DateTime.Now.TimeOfDay.Hours, DateTime.Now.TimeOfDay.Minutes, DateTime.Now.TimeOfDay.Seconds);
if ((now > start) && (now < end))
{
_block = true;
}
else
{
_block = false;
}
}
}
A massive thanks to anyone who can spot what's going wrong.
I have a hunch that the problem is your use of Application.Run(lockForm = new LockForm());. As per http://msdn.microsoft.com/en-us/library/ms157902(v=vs.110).aspx, "This method adds an event handler to the mainForm parameter for the Closed event. The event handler calls ExitThread to clean up the application."
So, it's doing what you told it - binding the lifetime of the application to the lifetime of the newly created LockForm.
Hope this helps.
Related
My questions is a bit generic, because I'm still trying to understand how to correctly implement that, however, given I have this code:
class Class1
{
public static void Something()
{
if (a)
{
//do something in a;
if (b)
{
//do something in b;
if (c)
{
//do something in c;
if (d)
{
while (Process.GetProcessesByName("ProcessName").Length > 0)
{
//execute action
return;
}
if (Process.GetProcessesByName("ProcessName").Length <= 0)
{
//execute action when the ProcessName is closed
...
//start the loop from beginning
Something();
}
}
}
}
}
}
}
What I want to achieve is:
Loop starts with Something(), until it reaches the if (d) condition, then I want to run certain actions in loop until a given process name is running, maybe using a new thread for performance(?). Once the process name is not found anymore, I want to do some other actions, and then start again from the beginning. Is that possible?
What would be the best way to achieve that?
Not sure if this is quite what you're after...but it ~might~ be a good start?
class Class1
{
private static bool a=true, b=true, c=true;
private static bool d()
{
Console.WriteLine("Launching Notepad");
Process P = Process.Start("notepad");
Console.WriteLine("Waiting for Notepad");
P.WaitForInputIdle();
Console.WriteLine("Notepad is ready!");
return true;
}
public static void Something()
{
while (true) // not sure how/when this exits
{
if (a)
{
//do something in a;
if (b)
{
//do something in b;
if (c)
{
//do something in c;
if (d())
{
// we'll assume after "d", the process has started
Process P = Process.GetProcessesByName("notepad").FirstOrDefault();
if (P != null)
{
P.EnableRaisingEvents = true;
P.Exited += (s, e) => {
//execute action when the ProcessName is closed
Console.WriteLine("Notepad closed.");
};
// execute action here?
Console.WriteLine("Action before loop.");
int counter = 1;
while (!P.HasExited)
{
// execute action or here?
Console.WriteLine("Waiting for Notepad to close: " + counter.ToString());
System.Threading.Thread.Sleep(1000); // check every second?
counter++;
}
}
}
}
}
}
}
}
}
Is this running in a WinForms app? Console app? Something else?...
I have been trying to work out why my background worker is 'finishing' its work when there is still a lot for it to do. I am actually in the process of refactoring the code for this app, so it did work in the past, but now I am unable to figure out what has gone wrong.
Specifically, the app should open Outlook and then perform a few checks. However, the background worker exits straight after Outlook is opened for no apparent reason (as you will se below there is still plenty of processing to be done).
This appears to be happening early on in the Start() method, directly after calling Process.Start() on Outlook.exe.
The code runs in this order:
calling the background worker - this was the user's choice from a radio set
....
else if (radioButton5.Checked == true)
{
textBox1.Text = "Please wait while your session restarts";
pageControl1.SelectedIndex = 10;
backgroundReset.RunWorkerAsync();
}
The do-work method
public void backgroundReset_DoWork(object sender, DoWorkEventArgs e)
{
backgroundReset.WorkerSupportsCancellation = true;
Session.Reset();
}
the reset session method starts by killing the current session ...
public static void Reset()
{
KillSession();
System.Threading.Thread.Sleep(5000);
Start();
// THE BACKGROUNDWORKER EXITS BEFORE HERE!
if (IsLoggedIn() == false)
{
return;
}
else
{
// Make sure Lync is open before finishing the process ...
var j = 0;
GetSession(Init.servers);
j = 0;
var checker = false;
checker = ProcessHandler.CheckRunning("lync.exe");
while (checker == false)
{
if (j == 100)
{
break;
}
Thread.Sleep(500);
checker = ProcessHandler.CheckRunning("lync.exe");
j++;
}
}
}
As you can see from the comment, the backgroundworder is calling RunWorkerCompleted way before the Reset() method has finished executing.
Below are the other methods called (kill, logoff, start):
KillSession logs the session of and then makes sure it is logged off
private static void KillSession()
{
if (sessionId != null)
{
LogOff();
for (int i = 0; i < 150; i++)
{
if (IsLoggedIn() == true)
{
Thread.Sleep(500);
}
else
{
break;
}
}
}
}
LogOff sends a Cmd command to log off the current session
public static void LogOff()
{
string strCmdIn = "/C LOGOFF " + sessionId + " /SERVER:" + serverName;
Cmd.Exec(strCmdIn);
}
Start() Simply opens Outlook, causing a Citrix session to also start. The app is definitely launching Outlook, but after that it doesn't reach either of the for statements - the BackgroundWorker just exits.
public static void Start()
{
Process.Start(appDataCitrix + "Outlook.exe");
for (int i = 0; i < 15; i++)
{
if (IsLoggedIn2() == false)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
if (IsLoggedIn2() == false)
{
Process.Start(appDataCitrix + "Outlook.exe");
for (int i = 0; i < 10; i++)
{
if (IsLoggedIn2() == false)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
}
}
Does anyone have any idea what is going on here? It is driving me crazy!
Many thanks
Update
The RunWorkerCompleted Method:
As far as my understanding goes, this has no baring on when the process will finish.
public void backgroundReset_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Session.IsLoggedIn())
{
btnFailFinish.Visible = true;
label10.Text = Session.serverName;
pageControl1.SelectedIndex = 3;
}
else
{
pageControl1.SelectedIndex = 10;
pictureBox2.Visible = false;
textBox1.Text = "Double-click Outlook on your desktop to launch a new session.";
textBox15.Text = "Once you have done this please click Finish.";
pictureBox9.Visible = true;
}
}
This is probably because of an exception being thrown from within the start method.
You may either add a try / catch block all around this method and handle the error from within the catch, or check in the RunWorkerCompleted method if an exception occurred :
private void RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// handle your exception here
}
}
I have a probably simple question about the task factory. I have to following code:
In this task is a loop that is polling data from the RS232 and a counter that stops polling after 10 times. After this "doCollect" will be set to false.
And now comes the strange thing: The task runs repeatedly. The caller code is:
// class Main()
RS232DataAquisition _RS232DataAquisition = new RS232DataAquisition();
public override void Run()
{
System.Diagnostics.Stopwatch timeout = new System.Diagnostics.Stopwatch();
timeout.Start();
_RS232DataAquisition.Start();
while ((timeout.ElapsedMilliseconds <= (dataGatherTime_inSeconds * 1000)) && _RS232DataAquisition.DoCollect)
{
System.Threading.Thread.Sleep(100);
}
timeout.Stop();
_RS232DataAquisition.Stop();
}
Per my understanding the Run() function should start the thread and return into the while-loop waiting for the thread to finish. But it never does?!
Here's the code for ReadDataFromRS232:
// sealed class RS232DataAquisition
private bool doCollect = false;
public bool DoCollect
{
get { return doCollect; }
}
public void Start()
{
doCollect = true;
currentTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
this.ReadDataFromRS232();
});
}
private void ReadDataFromRS232(int NumtoRead = 10)
{
var port = new System.IO.Ports.SerialPort(PortName);
int waitCount = 5;
var portExists = System.IO.Ports.SerialPort.GetPortNames().Any(x => x == PortName);
if (!portExists)
{
throw new ArgumentException("Port does not exist!");
}
while (port.IsOpen && waitCount-- > 0)
{
doCollect = false;
Wait();
}
doCollect = true;
if (!port.IsOpen)
{
port.Open();
port.NewLine = _NewLine;
port.ReadTimeout = 2000;
int number;
try { }
finally { }
port.Write("flashon\r");
while (doCollect && (_readCounter <= NumtoRead))
{
string s;
try
{
s = port.ReadLine();
}
catch
{
s = "-1";
}
int i;
if (int.TryParse(s, out i))
{
number = Convert.ToInt32(s, 10);
}
else
{
number = 0;
}
lock (thisLock) _data.Add(number);
_readCounter++;
}
port.Write("flashoff\r");
port.Close();
port.Dispose();
Wait(); Wait();
}
}
private void Wait()
{
System.Threading.Thread.Sleep(10);
System.Threading.Thread.SpinWait(1);
}
I don't get, why "ReadDataFromRS232" is beeing repeated until the timeout stops this task.
Thank you for any help :)
EDIT: Added some missing code.
As Dennis said the problem seemed to come from the missing volatile. It works now even though I have no idea why it didn't before.
I have the following code that starts some threads:
List<Stuff> lNewStuff = new List<Stuff>();
// populate lNewStuff
for (int i = 0; i < accounts.Length; i++)
{
Account aTemp = _lAccounts.Find(item => item.ID == accounts[i]);
Thread tTemp = new Thread(() => aTemp.ExecuteMe(lNewStuff));
tTemp.Start();
}
Then in the Account class you have the ExecuteMe method that has a lock:
public class Account
{
private Object lockThis = new Object();
public void ExecuteMe(List<Stuff> lNewStuff)
{
//Ensure only one thread at a time can run this code
lock (lockThis)
{
//main code processing
}
}
}
Now, sometimes the thread starts with lNewStuff == null since it sometimes does not find any New Stuff with the Account ID. This is normal for this project. The thread should always try to run but when null I want this thread to die and not wait when a lock is encountered.
So specifically:
If lNewStuff is null and there is a lock then terminate the thread. (how to do this?)
If lNewStuff is null and there is no lock then run normally (does this already)
If lNewStuff is not null and there is a lock then wait for the lock to finish (does this already)
if lNewStuff is not null and there is no lock then run normally (does this already)
When lNewStuff is null you could use Monitor.TryEnter and only continue if the lock is granted:
public class Account
{
private readonly object lockThis = new object();
public void ExecuteMe(List<Stuff> lNewStuff)
{
bool lockTaken = false;
try
{
if (lNewStuff == null)
{
// non-blocking - only takes the lock if it's available
Monitor.TryEnter(lockThis, ref lockTaken);
}
else
{
// blocking - equivalent to the standard lock statement
Monitor.Enter(lockThis, ref lockTaken);
}
if (lockTaken)
{
// main code processing
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(lockThis);
}
}
}
}
If lNewStuff is null and there is a lock then terminate the thread. (how to do this?) ,
do you want to still start a thread if lNewStuff is Null if answer is no then solution must be very simple.
List<Stuff> lNewStuff = new List<Stuff>();
// populate lNewStuff
for (int i = 0; i < accounts.Length; i++)
{
Account aTemp = _lAccounts.Find(item => item.ID == accounts[i]);
if(lNewStuff!=null)
{
Thread tTemp = new Thread(() => aTemp.ExecuteMe(lNewStuff));
tTemp.Start();
}
}
also you shd create a single lock object
private Object lockThis = new Object(); // this statement is creating new lock object with every account object, and hence does not ensure critical section protection.
Change this to
private static Object lockThis = new Object();
Just to be different:
public class Foo : IDisposable
{
private Semaphore _blocker;
public Foo(int maximumAllowed)
{
_blocker = new Semaphore(1,1);
}
public void Dispose()
{
if(_blocker != null)
{
_blocker.Dispose();
_blocker.Close();
}
}
public void LimitedSpaceAvailableActNow(object id)
{
var gotIn = _blocker.WaitOne(0);
if(!gotIn)
{
Console.WriteLine("ID:{0} - No room!", id);
return;
}
Console.WriteLine("ID:{0} - Got in! Taking a nap...", id);
Thread.Sleep(1000);
_blocker.Release();
}
}
Test rig:
void Main()
{
using(var foo = new Foo(1))
{
Enumerable.Range(0, 10)
.Select(t =>
Tuple.Create(t, new Thread(foo.LimitedSpaceAvailableActNow)))
.ToList()
.AsParallel()
.ForAll(t => t.Item2.Start(t.Item1));
Console.ReadLine();
}
}
Output:
ID:4 - Got in! Taking a nap...
ID:8 - No room!
ID:0 - No room!
ID:7 - No room!
ID:2 - No room!
ID:6 - No room!
ID:5 - No room!
ID:9 - No room!
ID:1 - No room!
ID:3 - No room!
This is the form code and every time I test some inputs, the application will open and then immediately close and I can't figure out what is causing it.
namespace Assignment2
{
public partial class IsmClassForm : Form
{
public IsmClassForm()
{
InitializeComponent();
}
private void IsmClassForm_Load(object sender, EventArgs e)
{
}
protected Student m_student;
protected Course m_course;
protected IsmClassForm m_next;
protected EnrollmentForm m_home;
public bool TestPrerequisites()
{
if (!m_student.Record.MeetsPrerequisites(m_course.Number))
{
MessageBox.Show("The registrar reports that you don't meet the prerequisites for " + m_course.Prefix + m_course.Number.ToString());
m_student.PridePoints = m_student.PridePoints - 5;
m_student.Record.Remove(m_course);
return false;
}
return true;
}
public string Description
{
get
{
return textDescription.Text;
}
set
{
textDescription.Text = value;
}
}
public string Title
{
get
{
return this.Text;
}
set
{
this.Text = value;
}
}
public string Welcome
{
get
{
return labelWelcome.Text;
}
set
{
labelWelcome.Text = value;
}
}
public bool Initialize(Student student, int course, IsmClassForm next, EnrollmentForm home)
{
if (student == null) return false;
m_student = student;
m_next = next;
m_home = home;
m_course = m_student.Record.FindEnrolled(course);
if (m_course == null)
{
return false;
}
labelCourse.Text = m_course.Prefix + "-" + m_course.Number.ToString();
return TestPrerequisites();
}
public enum DropMode
{
FreeDrop, PayDrop, Withdraw, NoDrop
};
DropMode mState = DropMode.FreeDrop;
public DropMode Drop
{
get
{
return mState;
}
set
{
mState = value;
UpdateDrop();
}
}
public void UpdateDrop()
{
switch (Drop)
{
case DropMode.FreeDrop:
buttonDrop.Text = "Drop";
break;
case DropMode.PayDrop:
buttonDrop.Text = "Drop";
break;
case DropMode.Withdraw:
buttonDrop.Text = "Withdraw";
break;
case DropMode.NoDrop:
buttonDrop.Text = "Done";
break;
}
}
protected void buttonDrop_Click(object sender, EventArgs e)
{
switch (Drop)
{
case DropMode.FreeDrop:
m_student.PridePoints = m_student.PridePoints - 5;
m_student.Record.Remove(m_course);
m_course = null;
break;
case DropMode.PayDrop:
m_student.PridePoints = m_student.PridePoints - 10;
m_student.WealthPoints = m_student.WealthPoints - 500;
m_student.Record.Remove(m_course);
m_course = null;
break;
case DropMode.Withdraw:
m_student.PridePoints = m_student.PridePoints - 50;
m_student.WealthPoints = m_student.WealthPoints - 500;
m_course.Grade = "W";
break;
case DropMode.NoDrop:
m_student.WealthPoints = m_student.WealthPoints - 500;
break;
}
Close();
}
protected void IsmClassForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
//The student not having a grade suggest the buttons were ignored
if (m_course != null && m_course.Grade == null)
{
m_course.Grade = "F";
m_student.PridePoints = m_student.PridePoints - 100;
m_student.WealthPoints = m_student.WealthPoints - 500;
}
if (m_next != null) m_next.Show();
else if (m_home != null) m_home.Show();
}
}
And here are some test inputs:
static void TestIsmClassForm()
{
Student tjt1 = new Student("Travis Todd");
tjt1.Record = new Transcript();
tjt1.Record.Add(new Course(1, 3113, "B", false));
tjt1.Record.Add(new Course(1, 3232, "C", false));
tjt1.Record.Add(new Course(2, 3113, "A", true));
tjt1.Record.Add(new Course(2, 3232, null, true));
tjt1.Record.Add(new Course(2, 4220, null, true));
IsmClassForm f4220 = new IsmClassForm();
IsmClassForm f3232 = new IsmClassForm();
IsmClassForm f4212 = new IsmClassForm();
f4212.Initialize(tjt1, 4212, f3232, null);
f3232.Initialize(tjt1, 3232, f4220, null);
f4220.Initialize(tjt1, 4220, null, null);
f4212.Show();
}
This does use some other classes in the project and their forms, but I the other functions all work and these is the only problem I have found so far. Am I missing something glaringly obvious?
Thank you,
Travis
You have two ways to achieve this;
Given your entry method:
public static void Main()
{
TestIsmClassForm();
}
You can use Application.Run or Form.ShowDialog:
static void TestIsmClassForm()
{
...All of your original code...
Application.Run(f4212.Show());
//OR
f4212.ShowDialog()
}
What is happening right now is that Form.Show is non-blocking - the application calls it, continues on out of the method, and closes.
Application.Run will show the form and wait until it closes before exiting the application. Form.ShowDialog() will block the calling method until the form is closed.
Application.Run is preferred because it guarantees the form used as the application host is marshalled in the "Main" or "GUI" thread. ShowDialog() makes no guarantee when run direct from Main()(Application.MessageLoop is false) and it is possible for some surprisingly annoying threading bugs to happen - so the majority of the time Application.Run is the best way to achieve what you are doing.
Make sure there is a Program.cs (that's the default name) file in your project. It should have void Main(string[] args) method, which will construct an instance of the form (namely, form1) and do Application.Run(form1).
Place breakpoints in IsmClassForm_Load and IsmClassForm_FormClosed to catch the moments of the form opening and closing.
The reason the form disappears is that the variable/object that contains the form goes out of scope and is disposed off at the end of your test block.
i.e. As soon as the 'code' reaches the closing '}' all of those form (and the Student) variables will be disposed of.
You could replace the .Show(), with .ShowDialog() which will cause the code to stop until the form is manually closed.
MSDN: ShowDialog
MSDN: Variable and Method Scope