I have this basic code that will check for notepad running every minute.
namespace Watcher
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; ; i--)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("notepad"))
{
Console.WriteLine("True");
}
Console.WriteLine("NFalse");
}
Thread.Sleep(10000);
}
}
}
}
The problem is that it returns "NFalse" for every running process (It will print 100 of them for example). How can I just make this print once to show that the process is not running?
Refactor your code.
You're doing too much in one method. Put your code that checks to see if notepad is running into a separate method:
static bool CheckIfProcessIsRunning(string nameSubstring)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains(nameSubstring))
{
return true;
}
}
return false;
}
You could simplify this further using LINQ:
static bool CheckIfProcessIsRunning(string nameSubstring)
{
return Process.GetProcesses().Any(p => p.ProcessName.Contains(nameSubstring));
}
Once you have written this method, all that remains is to call it and print the right message depending on whether it returns true or false.
while (true)
{
string message = CheckIfProcessIsRunning("notepad") ? "True" : "NFalse";
Console.WriteLine(message);
Thread.Sleep(10000);
}
Now instead of one long method with complex logic, you have two very simple methods.
You just need to check the process you are interested in. Don't bother looping over all the running processes. Use Process.GetProcessByName().
for (int i = 0; ; i--)
{
Process[] processes = Process.GetProcessByName("notepad++"); // Without extension
if(processes.Length > 0){
Console.WriteLine("True");
}
else{
Console.WriteLine("False");
}
Thread.Sleep(10000);
}
Just change to this, so you only print out once.
var b = false;
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("notepad"))
{
if (!b) b = true;
}
}
Console.WriteLine(b);
Well this seems to work well.
Dim x = Process.GetProcesses().ToList().FirstOrDefault(Function(p) p.ProcessName.Contains("Notepad"))
if x Is Nothing then
Console.WriteLine("false")
end if
Related
I have a class that executes my function but the variable changes too fast for me to even append my file. I need the speed but I need the functionality in my multithreading. Here's what's in my program.cs that's really the main key in multithreading.
process process = new process();
Thread[] threads = new Thread[15];
static int refInt = 0;
for (int i = 0; i < threads.Count(); i++)
{
threads[i] = new Thread(process.checkCookies);
}
foreach (Thread threadStart in threads)
{
threadStart.Start();
}
That's my program.cs and here's my process library.
public void checkCookies()
{
try
{
while (Interlocked.Increment(ref refInt) < cookies.Count)
{
try
{
string data = functions.cookieToUserId(cookies[refInt]);
if (data == "The cookie is incorrect.")
{
ConsoleWrite("\nThe cookie is invalid.", ConsoleColor.DarkRed);
continue;
}
string cookiesValue = functions.getRobux(cookies[refInt]);
if (cookiesValue == "Invalid cookie.")
{
ConsoleWrite("\nThe cookie is invalid.", ConsoleColor.DarkRed);
continue;
}
else if (Convert.ToInt32(cookiesValue) < 5)
{
ConsoleWrite(string.Format("\nThe account has less than 5 currency. [{0}]", data), ConsoleColor.DarkRed);
continue;
}
else if (Convert.ToInt32(cookiesValue) > 5)
{
ConsoleWrite(string.Format("\nThe account has {0} currency. [{1}]", cookiesValue, data), ConsoleColor.DarkGreen);
functions.appendFile("config/checkedCookies.txt", cookies[refInt]);
continue;
}
}
catch
{
//exception
}
}
}
catch
{
//exception
}
}
My issue is that whenever there is a cookie with a currency integer greater than 5, when it appendsFile which is basically this function here.
public string appendFile(string file, string content)
{
try
{
using (StreamWriter writeStream = File.AppendText(file))
{
writeStream.WriteLine(content);
return "Appended the text successfully!";
}
}
catch (Exception)
{
return "Error appending the text.";
}
}
The refInt changes due to another thread running it. So if refInt is equal to 4, then after it goes through all the else if statements. The refInt changes to 20-25 because of the other threads running the code and changing the global variable so whenever I append text, it appends the wrong cookie. What are some methods to make it so the global variable doesn't get changed too fast, by the way. I need the speed to be as fast as that.
i dont know if its helps or kills ur multithreading idee but did u ever think about mutex lock?
https://www.c-sharpcorner.com/UploadFile/1d42da/threading-with-mutex/
I was just curious if there was a simplified way to write this bit of code, or more efficient.
I want to wait for a new notepad.exe to exist, add that process to a list of processes or list of process ids only if it is not already in the list, also remove any processes in that list that do not exist anymore. Then repeat in an endless loop.
public static List<int> Clients = new List<int>();
while(true)
{
foreach (int r in Clients)
if (!ProcessExists(r))
{
Clients.Remove(r);
Console.WriteLine(r + " was removed.");
break;
}
bool check = false;
Process[] initial = Process.GetProcessesByName("notepad");
foreach (Process i in initial)
{
foreach(int r in Clients)
{
if (i.Id == r)
{
check = true;
}
}
if (check == false)
{
Clients.Add(i.Id);
Console.WriteLine(i.Id + " was added.");
}
check = false;
}
Thread.Sleep(250);
}
private static bool ProcessExists(int id)
{
return Process.GetProcessesByName("notepad").Any(x => x.Id == id);
}
The first loop that take care of deletion can be simpler using Linq:
Clients.RemoveAll(p => !ProcessExists(p));
Or this way, to keep the log:
Clients.RemoveAll(p => {
if (!ProcessExists(p)) {
Console.WriteLine(p + " was removed.");
return true;
}
return false;
});
For the second loop, you can use Contains() method of the List<> class:
Process[] initial = Process.GetProcessesByName("notepad");
foreach (Process i in initial)
{
if (!Clients.Contains(i.Id))
{
Clients.Add(i.Id);
Console.WriteLine(i.Id + " was added.");
}
}
I wrote a short Program which searches for empty directories and deletes them.
This process should run in background while a second process should write something to the Console every second so that the user knows the program is still running.
My problem is that the whole program stops after about 3 seconds while the processDirectory method didn't even finish.
My Main Method which calls a Method (processDirectory()) which runs in a second Thread:
static void Main(string[] args)
{
Thread delEmpty = new Thread(() => Thread2.processDirectory(#"C:\Users\Mani\Documents"));
delEmpty.Start();
printRunning(delEmpty);
File.WriteAllLines(#"C:\Users\Mani\Desktop\Unauthorized Folders.txt", Thread2.unauthorized);
File.WriteAllLines(#"C:\Users\Mani\Desktop\Empty Folders.txt", Thread2.emptyFolders);
Console.ReadKey();
}
My second Class which stores my processDirectory Method which should run in background:
public static List<string> unauthorized = new List<string>();
public static List<string> emptyFolders = new List<string>();
public static void processDirectory(string rootPath)
{
if (!Directory.Exists(rootPath)) return;
foreach (var dir in Directory.GetDirectories(rootPath))
{
try
{
processDirectory(dir);
if (Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0) Directory.Delete(dir, false);
}
catch (UnauthorizedAccessException uae) { unauthorized.Add(uae.Message); }
}
}
Code for printing something:
static async void printRunning(Thread delEmpty)
{
Console.CursorVisible = false;
for (int cnt = 1; delEmpty.IsAlive; cnt++)
{
switch (cnt)
{
case 1:
Console.Write("Running. ");
break;
case 2:
Console.Write("Running . ");
break;
case 3:
Console.Write("Running .");
cnt = 0;
break;
}
await Task.Delay(1000);
}
Console.Write("Finished!");
Console.CursorVisible = true;
}
I'm going to suggest that you avoid using threads and use an abstraction that deals with your threading issues for you. I suggest making use of Microsoft's Reactive Framework Team's Reactive Extensions (NuGet "System.Reactive") and Interactive Extensions (NuGet "System.Interactive").
Then you can do this:
static void Main(string[] args)
{
var rootPath = #"C:\Users\Mani\Documents";
using (Observable
.Interval(TimeSpan.FromSeconds(1.0))
.Subscribe(x => Console.WriteLine($"Running{"".PadLeft((int)x % 3)}.")))
{
Thread2.processDirectory(rootPath);
}
}
public static class Thread2
{
public static List<string> unauthorized = new List<string>();
public static List<string> emptyFolders = null;
public static void processDirectory(string rootPath)
{
if (!Directory.Exists(rootPath)) return;
emptyFolders =
EnumerableEx
.Expand(Directory.GetDirectories(rootPath), dir => Directory.GetDirectories(dir))
.Where(dir => Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0)
.ToList();
emptyFolders
.AsEnumerable()
.Reverse()
.ForEach(dir =>
{
try
{
Directory.Delete(dir, false);
}
catch (UnauthorizedAccessException uae) { unauthorized.Add(uae.Message); }
});
}
}
The key elements here are:
the Observable.Interval that sets up a timer to display the "Running" message every second.
the EnumerableEx.Expand which recursively builds the list of folders to be deleted.
the Reverse/ForEach which runs through the folders to be deleted (in reverse order) and deletes them.
It's important to not that the deleting happens on the main thread - it's just the "Running" message that comes out on the other thread. If needed, though, it would be fairly easy to push the deleting to another thread, but it isn't necessary.
To handle the case when GetDirectories throws an error, use this code:
Func<string, string[]> getDirectories = dir =>
{
try
{
return Directory.GetDirectories(dir);
}
catch (UnauthorizedAccessException uae)
{
unauthorized.Add(uae.Message);
return new string[] { };
}
};
emptyFolders =
EnumerableEx
.Expand(getDirectories(rootPath), dir => getDirectories(dir))
.Where(dir => Directory.GetFiles(dir).Length == 0 && getDirectories(dir).Length == 0)
.ToList();
You can solve the issue by on of two ways:
Make your method printRunning run synchronously
Add delEmpty.Join() so main thread will wait while delEmpty thread finishes
delEmpty.Start();
printRunning(delEmpty);
delEmpty.Join();
In case of 1st solution replace the printRunning method with the following one
static void printRunning(Thread delEmpty)
{
Console.CursorVisible = false;
for (int cnt = 0; delEmpty.IsAlive; cnt++)
{
switch (cnt % 3)
{
case 0:
Console.Write("Running.");
break;
case 1:
Console.Write("Running..");
break;
case 2:
Console.Write("Running...");
break;
}
Thread.Sleep(1000);
Console.SetCursorPosition(0, 0);
Console.Clear();
}
Console.Write("Finished!");
Console.CursorVisible = true;
}
I am breaking a list into chunks and processing it as below:
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
do something
}
catch
{
print error
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
foreach (var item in sourceList)
{
chunkReturn.Add(item);
if (chunkReturn.Count == chunkSize)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
if (chunkReturn.Any())
{
yield return chunkReturn;
}
}
}
If there is an error, I wish to run the chunk again. Is it possible to find the particular chunk number where we received the error and run that again ?
The batches have to be executed in sequential order .So if batch#2 generates an error, then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good .
List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
//do something
}
catch
{
//print error
failedChunks.Add(partiallist);
}
}
// attempt to re-process failed chunks here
I propose this answer based on your comment to Aaron's answer.
The batches have to be executed in sequential order .So if 2 is a problem , then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good.
foreach (var partialist in breaklistinchunks(chunksize))
{
int fails = 0;
bool success = false;
do
{
try
{
// do your action
success = true; // should be on the last line before the 'catch'
}
catch
{
fails += 1;
// do something about error before running again
}
}while (!success && fails < 2);
// exit the iteration if not successful and fails is 2
if (!success && fails >= 2)
break;
}
I made a possible solution for you if you don't mind switching from Enumerable to Queue, which kind of fits given the requirements...
void Main()
{
var list = new Queue<int>();
list.Enqueue(1);
list.Enqueue(2);
list.Enqueue(3);
list.Enqueue(4);
list.Enqueue(5);
var random = new Random();
int chunksize = 2;
foreach (var chunk in list.BreakListinChunks(chunksize))
{
foreach (var item in chunk)
{
try
{
if(random.Next(0, 3) == 0) // 1 in 3 chance of error
throw new Exception(item + " is a problem");
else
Console.WriteLine (item + " is OK");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
list.Enqueue(item);
}
}
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
while(sourceList.Count > 0)
{
chunkReturn.Add(sourceList.Dequeue());
if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
}
}
Outputs
1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK
One possibility would be to use a for loop instead of a foreach loop and use the counter as a means to determine where an error occurred. Then you could continue from where you left off.
You can use break to exit out of the loop as soon as a chunk fails twice:
foreach (var partialList in breaklistinchunks(chunksize))
{
if(!TryOperation(partialList) && !TryOperation(partialList))
{
break;
}
}
private bool TryOperation<T>(List<T> list)
{
try
{
// do something
}
catch
{
// print error
return false;
}
return true;
}
You could even make the loop into a one-liner with LINQ, but it is generally bad practice to combine LINQ with side-effects, and it's not very readable:
breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));
This is a two part question.
I have a class that gets all processes asynchronously and polls them for CPU usage. Yesterday I had a bug with it and it was solved here.
The first part of the question is why the solution helped. I didn't understand the explanation.
The second part of the question is that I still get an "Object reference not set to an instance of object" exception occasionally when I try to print the result at the end of the process. This is because item.Key is indeed null. I don't understand why that is because I put a breakpoint checking for (process == null) and it was never hit. What am I doing wrong?
Code is below.
class ProcessCpuUsageGetter
{
private IDictionary<Process, int> _usage;
public IDictionary<Process, int> Usage { get { return _usage; } }
public ProcessCpuUsageGetter()
{
while (true)
{
Process[] processes = Process.GetProcesses();
int processCount = processes.Count();
Task[] tasks = new Task[processCount];
_usage = new Dictionary<Process, int>();
for (int i = 0; i < processCount; i++)
{
var localI = i;
var localProcess = processes[localI];
tasks[localI] = Task.Factory.StartNew(() => DoWork(localProcess));
}
Task.WaitAll(tasks);
foreach (var item in Usage)
{
Console.WriteLine("{0} - {1}%", item.Key.ProcessName, item.Value);
}
}
}
private void DoWork(object o)
{
Process process = (Process)o;
PerformanceCounter pc = new PerformanceCounter("Process", "% Processor Time", process.ProcessName, true);
pc.NextValue();
Thread.Sleep(1000);
int cpuPercent = (int)pc.NextValue() / Environment.ProcessorCount;
if (process == null)
{
var x = 5;
}
if (_usage == null)
{
var t = 6;
}
_usage.Add(process, cpuPercent);
}
}
The line
_usage.Add(process, cpuPercent);
is accessing a not-threadsafe collection from a thread.
Use a ConcurrentDictionary<K,V> instead of the normal dictionary.
The 'null reference' error is just a random symptom, you could get other errors too.