Code is still looping after break - c#

I have 3 instances of the same app running. If I have my program mark one to be killed, it works fine, and 2 remain running. When I mark another to be killed, then it kills the remaining 2, instead of just one more. If I put a messagebox before the "break;", it works correctly, only killing one more and leaving one running. But without the messagebox, when I try to kill the second instance, it always kills both that one and the third instance. Any idea why a messagebox there would make it work correctly? I'm assuming some type of timing issue, but I can't figure out why, since there's a "break;".
foreach (WatcherScraperModel scraper in this.Scrapers.Except(scheduled.Where(x => x.Active)))
{
totalinstances = 0;
foreach (Process process in Process.GetProcesses())
{
try
{
if (process.MainModule.FileName == scraper.FileName)
{
// get instances already running
totalinstances++;
}
}
catch
{
// certain core processes cannot be accessed, don't worry about it
}
}
foreach (Process process in Process.GetProcesses())
{
try
{
// only kill an instance if there's too many running
if (process.MainModule.FileName == scraper.FileName && totalinstances > scheduled.Count(x => x.Active && x.FileName == scraper.FileName))
{
logger.DebugFormat("Killed {0} because it was not scheduled to be running", scraper.FileName);
process.Kill();
scraper.RestartRemaining = 0;
break;
}
}
catch
{
// certain core processes cannot be accessed, don't worry about it
}
}
}

Check out the documentation for Process.Kill
The Kill method executes asynchronously. After calling the Kill method, call the WaitForExit method to wait for the process to exit, or check the HasExited property to determine if the process has exited.
If you add a process.WaitForExit(); after process.Kill(); then the next time you call Process.GetProcesses() that process should not longer be there allowing your count to be correct. This also explains why adding a message box fixes the problem as that will give the process time to stop before you continue with the outer foreach loop.

Related

How to run a exe file dependant on another exe file running

static Process[] processArray = new Process[1];
static void Main(string[] args)
{
bool programIsRunning = false;
string process = "file location file name .exe";
processArray = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(process));
Console.WriteLine(processArray);
do
{
if (processArray == null && programIsRunning == false)
{
Process.Start("file location file name .exe");
programIsRunning = true;
}
} while (true);
}
When i run this code and launch 1st exe the second one doesn't begin running (its supposed to). however if i do if (processArray != null && programIsRunning == false) the 2nd exe file runs even when the first isn't running.
Your biggest problem here is not enough code is in the loop (and its while(true)!)
Because you don't reset programIsRunning to false (and you really don't even need that variable), or re-get your Process array, only the first result will ever run (and really, it only runs if processArray is null which it probably isn't, just empty).
You really want something closer to:
string process = "file location file name .exe";
do
{
processArray = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(process));
Console.WriteLine(processArray);
if (!processArray?.Any() ?? false)
{
Process.Start(process);
}
Thread.Sleep(2000);//IMPORTANT: Sleep or you are doing expensive work in a tight loop!
} while (true);
Even that code could be improved immensely by putting your loop in a separate thread and having a condition on the while so you can shut it down properly, alternatively, just use a Timer. You also don't really need a loop at all since you can attach to the Exited event of the process you created in case it shuts down.

C# BackgroundWorker Exiting Unexpectedly

I have thef ollowing background worker in my app which is meant to start a user's session automatically if there is not already one available.
This is done on a backgroundworker (backgroundInit) on initialisation. As you can see below, I have a while loop which continues to run as long as the var checker remains false:
var checker = false;
var i = 0;
while (checker == false)
{
_session = funcs.GetSession(_servers, _name);
_sessID = _session[0].Trim();
_servName = _session[1];
checker = funcs.CheckRunning("lync.exe");
i++;
if (i > 200)
{
break;
}
}
The CheckRunning method just checks if a specified program (in this case, "lync") is currently running and returns either true or false accordingly (This is done via a CMD command).
When I run the app in an empty session however, the while loop only iterates one time before breaking out, even though "Lync" is definitely not running.
Is there any reason why running a process or too many processes from within a Backgroundworker may cause it to exit?
As the comments mentioned, this was not an issue with the BackgroundWorker, but rather an exception occurring at _sessID = session[0].Trim(); where the session had not yet started, so there is no ID.
To resolve this, I simply placed a Try/Catch block around this assignment, and let the program silently ignore the exception:
try
{
_sessID = _session[0].Trim();
_servName = _session[1];
}
catch (Exception exp)
{
// MessageBox.Show(exp.Message);
}
This works for me, as the loop will continue checking until the counter i reaches the 200 limit, at which stage the program will accept failure.

how to get PID of my app at runtime using C#

My app checks at startup if any other instance of the same is running already, if yes then it will close all other instances. For this I tried using Process.GetProcessByName("AppName") function and store all the process with AppName in processes[] array. Now i want to find the PID of current instance so that i can close all other instances of my app (which obviously have same name but different PIDs). But i am unable to find that even after lot of googling. Also how can i find the PID of an instance of my app which i have created with Process.Start("AppName.exe") function called from inside AppName.exe
OK, given problems with my other solution, see the following
In order to hook in between processes, you need some form of IPC. To use the simplicty of shared handles between EventWaitHandles, you could make each program listen for a cancellation flag.
public static EventWaitHAndle CancellationEvent =
new EventWaitHandle(
false,
EventResetMode.AutoReset,
"MyAppCancel");
private object lockObject = new object();
And later...
Task.Run(() =>
{
while(true)
{
CancellationEvent.WaitOne();
lock(lockObject)
if(!thisIsCalling) // static bool to prevent this program from ending itself
Environment.Exit(0);
}
}
And then call the cancellation like so
lock(lockObject)
{
thisIsCalling = true;
CancellationEvent.Set();
thisIsCalling = false;
}
Why don't you just check equality with your current process?
var processes = Process.GetProcessByName("AppName");
foreach (var p in processes)
{
if (p != Process.GetCurrentProcess())
p.CloseMainWindow();
}
If you're interested in closing other instances of your app, why not do the opposite and prevent multiple instances from opening in the first place? Using EventWaitHandle can do this thusly:
bool created;
var eve = new System.Threading.EventWaitHandle(
false,
EventResetMode.AutoReset,
"MyAppHandle",
out created);
if(!created)
{
eve.Set();
Environment.Exit(-1); // Always use an exit error code if you're expecting to call from the console!
}
The handle parameter, "MyAppHandle" in this case, will be shared across the entire system, thus meaning not only will the out created paramete be false on secondary instaces, but you can use eve.Set() to cause the handle to fire acorss application. Set up a listening thread and this can allow a message loop to display a message when you attempt to open second instance.
Task.Run(() =>
{
while(true)
{
eve.WaitOne();
// Display an error here
}
}

System.Core Pipe is broken

I currently just inherited some complex code that unfortunately I do not fully understand. It handles a large number of inventory records inputting/outputting to a database. The solution is extremely large/advanced where I am still on the newer side of c#. The issue I am encountering is that periodically the program will throw an IO Exception. It doesn't actually throw a failure code, but it messes up our output data.
the try/catch block is as follows:
private static void ReadRecords(OleDbRecordReader recordReader, long maxRows, int executionTimeout, BlockingCollection<List<ProcessRecord>> processingBuffer, CancellationTokenSource cts, Job theStack, string threadName) {
ProcessRecord rec = null;
try {
Thread.CurrentThread.Name = threadName;
if(null == cts)
throw new InvalidOperationException("Passed CancellationToken was null.");
if(cts.IsCancellationRequested)
throw new InvalidOperationException("Passed CancellationToken is already been cancelled.");
long reportingFrequency = (maxRows <250000)?10000:100000;
theStack.FireStatusEvent("Opening "+ threadName);
recordReader.Open(maxRows, executionTimeout);
theStack.FireStatusEvent(threadName + " Opened");
theStack.FireInitializationComplete();
List<ProcessRecord> inRecs = new List<PIRecord>(500);
ProcessRecord priorRec = rec = recordReader.Read();
while(null != priorRec) { //-- note that this is priorRec, not Rec. We process one row in arrears.
if(cts.IsCancellationRequested)
theStack.FireStatusEvent(threadName + " cancelling due to request or error.");
cts.Token.ThrowIfCancellationRequested();
if(rec != null) //-- We only want to count the loop when there actually is a record.
theStack.RecordCountRead++;
if(theStack.RecordCountRead % reportingFrequency == 0)
theStack.FireProgressEvent();
if((rec != null) && (priorRec.SKU == rec.SKU) && (priorRec.Store == rec.Store) && (priorRec.BatchId == rec.BatchId))
inRecs.Add(rec); //-- just store it and keep going
else { //-- otherwise, we need to process it
processingBuffer.Add(inRecs.ToList(),cts.Token); //-- note that we don't enqueue the original LIST! That could be very bad.
inRecs.Clear();
if(rec != null) //-- Again, we need this check here to ensure that we don't try to enqueue the EOF null record.
inRecs.Add(rec); //-- Now, enqueue the record that fired this condition and start the loop again
}
priorRec = rec;
rec = recordReader.Read();
} //-- end While
}
catch(OperationCanceledException) {
theStack.FireStatusEvent(threadName +" Canceled.");
}
catch(Exception ex) {
theStack.FireExceptionEvent(ex);
theStack.FireStatusEvent("Error in RecordReader. Requesting cancellation of other threads.");
cts.Cancel(); // If an exception occurs, notify all other pipeline stages, then rethrow
// throw; //-- This will also propagate Cancellation, but that's OK
}
In the log of our job we see the output loader stopping and the exception is
System.Core: Pipe is broken.
Does any one have any ideas as to what may cause this? More importantly, the individual who made this large-scale application is no longer here. When I debug all of my applications, I am able to add break points in the solution and do the standard VS stepping through everything to find the issue. However, this application is huge and has a GUI that pops up when I debug the application. I believe the GUI was made for testing purposes, but it hinders me from actually being able to step through everything. However when the .exe is run from our actual job stream, there is no GUI it just executes the way it's supposed to.
The help I am asking for is 2 things:
just suggestions as to what may cause this. Could an OleDB driver be the cause? Reason I ask is because I have this running on 2 different servers. One test and one not. The one with a new OleDB driver version does not fail (7.0 i believe whereas the other where it fails is 6.0).
Is there any code that I could add that may give me a better indication as to what may be causing the broken pipe? The error only happens periodically. If I run the job again right after, it may not happen. I'd say it's 30-40% of the time it throws the exception.
If you have any additional questions about the structure just let me know.

A better way of finding out if any running process was launched from a given file?

I have to check whether another process is running, based only on the name of the EXE file.
Currently I get the process list and then query the MainModule.FileName property, however some processes throw Win32Exception "Unable to enumerate the process modules" when you access the MainModule property.
Currently I am filtering to a 'safe list' by catching these access exceptions thus:
List<Process> processes = new List<Process>(Process.GetProcesses());
// Slow, but failsafe. As we are dealing with core system
// data which we cannot filter easily, we have to use the absense of
// exceptions as a logic flow control.
List<Process> safeProcesses = new List<Process>();
foreach (Process p in processes)
{
try
{
ProcessModule pm = p.MainModule;
// Some system processes (like System and Idle)
// will throw an exception when accessing the main module.
// So if we got this far, we can add to the safe list
safeProcesses.Add(p);
}
catch { } // Exception for logic flow only.
}
Needless to say I really don't like having to use exceptions like this.
Is there a better way to get the process list for which I can access the MainModule property, or even a better method of checking if any process was spawned from a given file?
I think that there are only System and Idle processes that will throw the exception so you can filter them out before and you're ready to go.
I will use like
List<Process> processes = Process.GetProcesses().ToList();
List<Process> safeProcesses = processes .Select(X =>
{
try { ProcessModule pp = X.MainModule; return X; }
catch { return null; }
}).Where(X=>X!=null).ToList();

Categories

Resources