Limit the Number of Created Processes - c#

I have two classes: Action class, that has a method for executing VBScript files, and Item class that contains a list of Action instances. My problem is that I want to limit the number of VBScript files that can be run at the same time. I have no experience with this, and I have googled and searched around, but found nothing. My only idea of how to do is is presented here:
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
namespace Test
{
public class Action
{
public string Script;
public static int Limit;
public static int ActiveCount = 0;
public Process process = new Process();
public Action(string script)
{
Script = script;
}
public void Execute()
{
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(Handler);
try
{
if (ActiveCount < Limit)
{
process = Process.Start(
"c:\\windows\\system32\\wscript.exe",
"\"" + Script + "\"");
ActiveCount++;
}
}
catch(Win32Exception e)
{
}
}
private void Handler(
object sender, EventArgs e)
{
ActiveCount--;
}
}
public class Item
{
public ArrayList Actions = new ArrayList();
}
class Program
{
static void Main()
{
Action.Limit = 5;
Item item = new Item();
item.Actions.Add(
new Action("C:\\Scripts\\Test_1.vbs"));
for (int i = 0; i < 10; i++)
{
foreach (Action action in item.Actions)
{
action.Execute();
Console.WriteLine(Action.ActiveCount);
}
}
}
}
}
The requirement of limiting the number of created processes seems common to me, but as I said, I haven't been able to find any samples I could build on. My question is: what is the common or usual way of doing this? (I also haven't been able to find any samples here on StackOverFlow, so if there are any, please post the link). Any hint or a link is welcome.

Well what you've got will work.
I'm not sure what the fact that you can't find more information tells you.
It's either that you're trying to solve a non-problem - but if your scripts are large and complex or need access to shared resources then limiting the number that run would seem to be a good idea; or it's that your solution is the right one and it's so trivial no one else has thought to raise it.

Related

Refresh UI from a method running asyncronously on another project

I had a winform using a method on another project thought a DLL, test, count and returns 2 values (good files and bad files) and show up on the winforms those 2 results once done.
Ive been asked to improve that winform to show up results in real time, since the work and the test can take up to 30mins, but ive been struggling since i'm beginning in async programmation.
Ive tried to call function with out or ref, without success. As far i tried, i can refresh in real time a local variable, but not one running in the method out of the winform project.
Winform :
public static int goodfiles { get; set; }
public static int badfiles { get; set; }
Task workControl;
Task refreshControl;
private async void Winform_Load(object sender, EventArgs e)
{
myprogressBar.Style = ProgressBarStyle.Marquee;
workControl = Task.Run(() => WorkMethod());
refreshControl = Task.Run(() => RefreshMethod());
await executerControl.ConfigureAwait(true);
}
private void RefreshMethod()
{
while (!workControl.IsCompleted)
{
label1.Invoke(new MethodInvoker(delegate
{
label1.Text = goodfiles.ToString();
label2.Text = badfiles.ToString();
}
}
}
private void WorkMethod()
{
goodfiles = 0;
badfiles = 0;
var Work = new WorkClass();
Work.ControlFiles(goodfiles, badfiles);
}
Class library project
public class WorkClass
{
public void ControlFiles(int goodfiles, int badfiles)
{
//Do stuff
var Test = new TestClass();
Test.TestFiles(goodfiles, badfiles);
}
}
public class TestClass
{
public void TestFiles(int goodfiles, int badfiles)
{
//Test files
if(stuff) goodfiles++;
else badfiles++;
}
}
I know it's maybe far from being the prefect architecture, but I have to deal with it.
Is it technically possible, difficult or just impossible to do? Or am I missing something obvious ?
You need to use the same fields from the worker thread and UI thread. The best way is to put them in a shared object. This might be the work-class, but you could also create a separate object that is given as a parameter to the actual work-method. I recommend against using any mutable static fields.
public class WorkClass
{
public volatile int GoodFiles;
public volatile int BadFiles;
public void ControlFiles()
{
//Test files
if (stuff) GoodFiles++;
else BadFiles++;
}
}
and call it like
WorkClass myWork;
private async void Winform_Load(object sender, EventArgs e)
{
myWork = new WorkClass();
workControl = Task.Run(() => myWork.ControlFiles());
}
To check the progress I would recommend a timer. Set it to run however often you want, and update the labels from the myWork-object when event handler for the Tick-event. You can await the workControl-task and stop the timer when the task is done.
It depends on how coupled or uncoupled you want your code to be.
In most cases, the Progress class is a good choice.
Here's an article from Stephen Cleary on the subject: Reporting Progress from Async Tasks

Releasing The Memory Used By Objects And Lists

I am trying to understand Garbage Collection process, and I think I got the idea. But when I works on some codes, It doesn't work as I expected.
In the code below, I just created 1.000.000 object and added them to a list. After a while, there is no object but memory stucks and not decreasing. How can I achieve to release the memory after all objects removed?
Thanks
private void button1_Click(object sender, EventArgs e)
{
List<Test> tesst = new List<Test>();
for (long i = 0; i < 1000000; i++)
{
using (Test test = new Test())
{
test.LongObj = i;
test.StrObj = i.ToString();
test.DecObj = Convert.ToDecimal(i);
tesst.Add(test);
}
}
Process proc = Process.GetCurrentProcess();
proc.Refresh();
label1.Text = Test.counter.ToString();
label2.Text = (proc.PrivateMemorySize64 / 1048576).ToString();
for (int i = 0; i < tesst.Count; i++)
{
tesst[i] = null;
}
tesst.Clear();
tesst = null;
}
private void button2_Click(object sender, EventArgs e)
{
Process proc = Process.GetCurrentProcess();
proc.Refresh();
label1.Text = Test.counter.ToString();
label2.Text = (proc.PrivateMemorySize64 / 1048576).ToString();
}
And the sample class
public class Test : IDisposable
{
public static long counter = 0;
public long LongObj { get; set; }
public string StrObj { get; set; }
public decimal DecObj { get; set; }
public Test()
{
Interlocked.Increment(ref counter);
}
~Test()
{
Interlocked.Decrement(ref counter);
}
public void Dispose()
{
}
}
Why exactly are you trying to release the memory manually? There are valid reasons, but I want to make sure you are in a situation that requires it.
You can force a garbage collection by calling GC.Collect() and optionally with a parameter telling it which generation to collect. You can read more about this here and it includes a similar test to what you are attempting to do.
How can I achieve to release the memory after all objects removed?
You don't, you let the GC do its job. Forcing the garbage collection (using System.GC.Collect()) is almost always a bad idea.
This really seems like a scenario where you need to rethink your process. I don't think this is a job for manually interacting with GC. Maybe if you post some of your code in a different question people can throw out some ideas on a different way to solve the problem?

use multithread to write into text files using C#

Hope you can help me with this one.i am beginner in multithreading programming with C#.
I am trying to build a program to write all numbers from range 1 to 2000 in two text files using two threads.
Every thread should write number from 1 to 2000 that not found at any of the two files "there is no duplicated numbers in the files" and every thread should't write the number that have been wrote by the another thread.
At the end if we merged the numbers of the two files we should have the numbers from 1 to 2000
Here is the source code i am trying but there is a problem in the writing for loop in the below image
i can't handle the process of writing by the two synchronized threads and i had exception:
Object synchronization method was called from an unsynchronized block of code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace Multithreading
{
class Program
{
static TextWriter file2 = new StreamWriter("file2 location");
static TextWriter file1 = new StreamWriter("file1 location");
static void Main(string[] args)
{
try
{
int[] array = new int[2000];
Thread thread1 = new Thread(Program.writeinfile1);
Thread thread2 = new Thread(Program.writeinfile2);
for (int counter = 1; counter <= 2000; counter++)
{
thread1.Start(counter);
thread2.Start(++counter);
Monitor.Enter(thread1);
Monitor.Wait(thread1);
Monitor.PulseAll(thread2);
}
}
catch (FileNotFoundException)
{
Console.WriteLine("the file you are trying to open is not found");
}
}
public static void writeinfile1(object x)
{
int converttointx = (int)x;
file1.WriteLine(converttointx);
file1.Close();
}
public static void writeinfile2(object y)
{
int converttointy = (int)y;
file2.WriteLine(converttointy);
file2.Close();
}
}
}
Here's an example of multi-threaded calls talking to one another to ensure they don't duplicate work.
I've not done exactly what you've asked for, since this looks quite homeworky; but hopefully this will help you to figure out the solution to your issue...
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
new Program();
Console.WriteLine("done");
Console.ReadKey();
}
Program()
{
int noThreads = 5;
int target = 2000;
StartThread(noThreads, target);
}
//kicks off our threads / waits for all threads to complete before returning
void StartThread(int noThreads, int target)
{
int id = noThreads--;
if (id > 0)
{
Doer doer = new Doer(id, target);
Thread t = new Thread(doer.Do);
t.Start();
StartThread(noThreads,target);
t.Join();
}
}
}
class Doer
{
static int marker = 0;
static readonly object syncLocker = new object();
readonly int id;
readonly int target;
public Doer(int id, int target)
{
this.id = id;
this.target = target;
}
public void Do()
{
while (marker < this.target)
{
int i;
lock (syncLocker)
{
i = ++marker;
}
System.Console.WriteLine("{0:00}: {1:###0}", id, i);
//Thread.Sleep(RandomNo()); //uncomment this & code below if your threads are taking turns / behaving too predictably
}
}
/*
static readonly Random rnd = new Random();
static readonly object rndSyncLocker = new object();
public static int RandomNo()
{
lock (rndSyncLocker)
{
return rnd.Next(0, 1000);
}
}
*/
}
}
You are not using the Monitor class correctly. The call to Monitor.PulseAll(thread2); should be called within thread the thread which owns the lock, which in this case would be within the writeinfile1 and writeinfile2 method.
This is why you are getting the exception:
Object synchronization method was called from an unsynchronized block of code.
See the following StackOverflow question for the correct way to use Monitor.PulseAll(object):
Help needed in Monitor.PulseAll()

Console.WriteLine not working?

I've created a program which should calculate the surface area of an irregular shaped object, such as a lake.
I read in a file, which contained the values for the x and y values, and the depth.
I'm new to C#, and so I don't fully understand everything yet, but I think my code should work, however, it doesn't seem to be writing the value for the area onto the screen.
I know that Console.WriteLine(_surface); SHOULD work , but it I can't seem to get it to do anything, and it's probably in the wrong place!
Can someone please tell me where I'm going wrong?
My code is as follows.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NUnit.Framework;
namespace ConsoleApplication1
{
public class ValueXyz
{
public double X { get; set; }
public double Y { get; set; }
public int Z { get; set; }
}
public class SurfaceCalculator
{
private ValueXyz[] _valuesXyz;
private double _surface;
private readonly string _textWithValues;
public SurfaceCalculator(string textWithValues)
{
_textWithValues = textWithValues;
SetValuesToCalculate();
}
public double Surface
{
get { return _surface; }
}
public void CalculateSurface()
{
for (var i = 0; i < _valuesXyz.Length; i++)
{
if (_valuesXyz[i].Z == 0)
_surface = (_valuesXyz[i].X * _valuesXyz[i + 1].Y) - (_valuesXyz[i + 1].X * _valuesXyz[i].Y);
Console.WriteLine(_surface);
}
}
private void SetValuesToCalculate()
{
var valuesXyz = _textWithValues.Split(' ');
_valuesXyz = valuesXyz.Select(item => new ValueXyz
{
X = Convert.ToDouble(item.Split(',')[0]),
Y = Convert.ToDouble(item.Split(',')[1]),
Z = Convert.ToInt32(item.Split(',')[2])
}).ToArray();
}
public void TestSurfaceCalculatorGetsAValue()
{
var textWithValues = File.ReadAllLines(#"C:\Users\user\Documents\Visual Studio 2010\Projects\Lake_Take_Toooooo\Lake_Take_Toooooo\bin\Debug\Lake_Test.csv");
var calculator = new SurfaceCalculator(_textWithValues);
calculator.CalculateSurface();
Assert.IsNotNull(calculator.Surface);
}
static void Main()
{
Console.ReadKey();
}
}
}
This is my first time using classes, so apologies if there's an obvious answer.
Thanks for your help!
You need to actually call the method inside the Main method, which is the program entry point. Like:
static void Main()
{
CalculateSurface();
Console.ReadKey();
}
When you run your program, only the code inside the Main method is actually executed. If you do not call anything from there then no code is executed.
No function is being called in the Main event...
I should imagine read key will wait for key input then close, correct?
Are you trying to run this as console application or as unit test? (It looks like you're trying to run it as unit test since you're using NUnit.Framework and there is a Test-method with an Assert...)
If you want to run it as console application, you have to call the code that should get executed in the Main method.
If you want to run it as unit test, you have to add some "attributes" to your test class and test method. The class should have the [TestFixture] attribute, and the method should have the [Test] attribute, like:
[TestFixture]
public class SurfaceCalculator {
...
[Test]
public void TestSurfaceCalculatorGetsAValue() {
...
}
}

Duplicate Logon Script

ok, so I'm writing a duplicate logon "worker" class in C# and I've ran into a bit of a snag. My logic behind it, I thought, was flawless! :(
But, I can't for the life of me figure out why it's triggering on the first occurence rather than on just duplicates :(
namespace Lab.Core.BackgroundWorker {
using Lab.Core;
using Lab.Core.Net;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
public class MultiLogon : IWorker {
private static Hashtable LoggedOnUsers = new Hashtable();
private Thread _worker = null;
//private Thread m_UsersUpdate = null;
public delegate Boolean AddUserToCollectionDelegate(String user, String computer);
public delegate void ClearCollectionDelegate(String user);
public delegate Boolean IsUserLoggedInDelegate(String user);
public Boolean AddUserToCollection(String user, String computer) {
int retVal = MultiLogon.LoggedOnUsers.Count + 1;
if (String.IsNullOrEmpty(user) || String.IsNullOrEmpty(computer))
return false;
if (!MultiLogon.LoggedOnUsers.ContainsKey(user))
MultiLogon.LoggedOnUsers.Add(user, computer);
return (MultiLogon.LoggedOnUsers.Count == retVal);
}
public void ClearCollection() {
if (MultiLogon.LoggedOnUsers.Count > 0)
MultiLogon.LoggedOnUsers.Clear();
}
public Boolean IsUserLoggedIn(String user) {
if (String.IsNullOrEmpty(user))
return false;
return (LoggedOnUsers.Contains(user));
}
#region IWorker Members
public void Run(object obj) {
AddUserToCollectionDelegate add = new AddUserToCollectionDelegate(AddUserToCollection);
//ClearCollectionDelegate clear = new ClearCollectionDelegate(ClearCollection);
//IsUserLoggedInDelegate isLogged = new IsUserLoggedInDelegate(IsUserLoggedIn);
while (true) {
foreach (Computer c in ComputerList.Instance)
if (!add.Invoke(c.UserName, c.MachineName)) {
// duplicate! or not? :/
// Credit (through adoption of code) goes to:
// http://bytes.com/groups/net-c/263778-quickly-finding-duplicates-arraylist#post1059834
foreach (DictionaryEntry item in MultiLogon.LoggedOnUsers) {
MessageBox.Show((String)item.Key, (String)item.Value);
//NetworkMessage.Send((String)item.Value, String.Format("It is against lab policy to share your account with anyone other than yourself or use someone else's account! Logout immediately or further action will be taken. Your action has been logged."));
//OffenseManager.Instance.AddOffense((String)item.Key, null, String.Format("Account sharing - Computer: {0}", item.Value), false);
}
}
Thread.Sleep(750);
}
}
public void Start() {
_worker = new Thread(new ParameterizedThreadStart(Run));
_worker.IsBackground = true;
_worker.Start();
}
public void Stop() {
if (_worker.IsAlive)
_worker.Abort();
}
#endregion
}
}
Apologies for the long code file. I don't know exactly what to paste to help you guys help me. :/
Thanks in advance! :)
Could be a thread race condition.
Have you tried to lock the collection when you're searching/inserting into it?
I don't believe Hashtable are threadsafe.
You might want to put a
lock(this) {
}
block around anything accessing the hashtable.

Categories