C# MultiThreading: pool of calculators - c#

I want to have a static (global) pool of calculators which are going to be accessed by a lot of different threads.
After some researching I found out that the elements of Arrays are threadsafe.
I thought that it would be good idea to store the diffrent calculators (amount unknown until runtime) in a static array (calculator[] calculators).
How do I ensure that only one calculator is being used by one calculator?
I read the whole msdn documentation so don't post "only" links please.
I have also thought about a bool array "locked" but I can't find a way to implement this threadsafe.
My code so far:
internal static class Calculators
{
private static Semaphore pool;
private static bool[] locked;
private static calcs[] neuralNetworks;
private static Thread[] threads;
internal static Calculators(){
int number = Globals.Number;
pool = new Semaphore(number, number);
locked = new bool[number];
calcs = new calcs[number];
threads = new Thread[number];
for (int index = 0; index < number; index++)
{
// all neuralNetworks are unlocked by default
locked[index] = false;
// generate one network per "countThreads"
calcs[index] = Globals.CalcObj;
// generate one thread for each neural network
threads[index] = new Thread(new ThreadStart());
}
}
private int WhichCalculators()
{
int index;
for (index = 0; index < countThreads; index++)
{
if (locked[index] == false)
{
locked[index] = true;
return index;
}
}
throw new Exception("Calculators was called, but there weren't any networks unused");
}
}
Code Update:
So should it work, if I call "WhichCalculator()" in this method?
private static void doStuff()
{
pool.WaitOne();
Monitor.Enter(thisLock);
try
{
int whichCalculator = WhichCalculator();
locked[whichCalculator] = true;
lock (calculators[whichCalculator])
{
Monitor.Exit(thisLock);
// do stuff
locked[whichCalculator] = false;
}
}
catch
{
Monitor.Exit(thisLock);
}
//Calculate();
pool.Release();
}
Question 2:
Am I right to assume, that the static constructor is going to be executed as soon as (but before) the first time this class or any member of it is going to be accessed?

Yes you have to use lock. But the array and every instance of calculator again.
If you can fill the array before you start the multithreaded section of your code you need not lock the array as well (only reading doesn't make problems due to the static content) but with resizing the array you need to lock every access to it (writing AND reading).
So your code could look like this:
Calculator calc = null;
lock(calculators)
{
calc = calculators[0];
}
lock(calc)
{
// ... do stuff
}
This way the array isn't longer locked then needed and you can lock the calculator itself.

You can lock your array. That would ensure that every array-operation is executed thread-safe.
To ensure, that each object is only used once at a time you can add a flag to it, like calculator.InUse. If you can't add a flag to the class, you can use an extension method.

Related

C# Accessing form control from different thread

I've been looking at https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls and other Stack Overflow questions for a good long while now to figure out how to use thread-safe methods to access a ListView controls from different threads.
Here's how I want to implement parallel tasks in my program:
I call four different methods in parallel with:
Parallel.Invoke(ProcessLow, ProcessMed, ProcessHigh, ProcessSprint);
Each method searches through the same collection (data[i].Knots) with a for loop and looks for a different range of values within that collection, then if one of the methods finds an appropriate value within the range it's looking for it adds the time and knots (data[i].Time, data[i].Knots) to its respective ListView (the methods write to lstvLow, lstvMed, lstvHigh and lstvSprint respectively). At the moment it's just throwing the exception for non-thread safe code. Also will it break if I have different threads just reading off the same collection? (if so, how can I work around this?)
tldr: Parallel processing is new to me, how do I make a thread-safe call to a windows form control.
And also if you can, point me in the direction of some good reading other than msdn for Parallel tasking.
edit: this is with winforms
To make thread safe call. use Control.Invoke(); method. Assuming you have instance of ListView mylistView; you can write:
object result = mylistView.Invoke(new Action(() => mylistView.DoSomething()));
As I understand, you are new to multitasking. I hope my case study will help you. Create a windows form with next controls:
startButton, stopButton as Button
minTextEdit, maxTextEdit as TextEdit
listListView as ListView
For startButton and stopButton use the appropriate methods: startButton_Click and stopButton_Click.
Full the code below:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Thread0
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private static readonly Random _random = new Random();
private List<int> lst = new List<int>();
private bool isRun = false;
private void startButton_Click(object sender, EventArgs e)
{
isRun = true;
stopButton.Enabled = true;
startButton.Enabled = false;
var tskMain = Task.Run(() =>
{
for (int i = 0; i < 8; i++)
{
var tsk1 = Task.Run(() =>
{
while (true)
{
int max = 0;
int min = Int32.MaxValue;
lock (lst)
{
int num = _random.Next(1, 1000000);
lst.Add(num);
foreach (var x in lst)
{
if (x > max) max = x;
if (min > x) min = x;
}
listListView.BeginInvoke(new Action(() => listListView.Items.Insert(0, num.ToString())));
}
maxTextBox.BeginInvoke(new Action(() => maxTextBox.Text = max.ToString()));
minTextBox.BeginInvoke(new Action(() => minTextBox.Text = min.ToString()));
if (!isRun) break;
Thread.Sleep(100);
}
});
}
});
}
private void stopButton_Click(object sender, EventArgs e)
{
isRun = false;
stopButton.Enabled = false;
startButton.Enabled = true;
}
}
}
When you click on the Start button, the stream create and run tskMain thread, which creates 8 more threads. In each of them, an integer is added to the list of values lst, and the search for the maximum and minimum values. The new number is also added to the listListView, and the maximum and minimum value in the corresponding minTextEdit and maxTextEdit.
For work it is convenient to use lambda expression.
lock(lst) ... blocks work with the list of values. One action per time, so that there are no exceptions.
And the BeginInvoke method allows you to call methods from threads for form elements that are in the main form stream. The Action is used to "transform" the lambda expression into a delegate method.
Inside each thread, the variable IsRun is checked, if its value becomes false, the thread execution stops.
Well, to ensure that everything is not very quickly use .Sleep

Property of { return 60000 / bpm } always returning 600ms?

I'm trying to build a steady metronome that ticks every beat, but it seems like there is a problem.
How long the metronome waits for each beat is determined by this formula: 60000 / BPM
But, the value seems to return a specific number no matter what value you plug into BPM.
I have a property that returns the value of this formula, along with a bpm integer:
static private int bpm = 125;
static private int BeatLength
{
get
{
return 60000 / bpm;
}
}
static public int beat = 0;
And here is the function that's responsible for the metronome (it runs on a dedicated thread):
public static void RhythmUpdate()
{
lock (threadLock)
{
while (true)
{
Thread.Sleep(BeatLength); // Sleep until the next beat
AddRequest(BeatLength * beat);
beat++;
DefaultSounds.def_CowBell.Play();
OnBeat?.Invoke();
}
}
}
When breakpointing the def_CowBell.Play();, Visual Studio notes that it takes around 600ms to loop. This is how I know the value.
Extra Info:
I'm using OpenGL
Maybe some more if asked...
I appreciate your help in advance.
It turns out that I've been setting BPM on a function, and whenever I made a change to it's initialization it would be overwritten by that new BPM.
public static void StartBeat(int startingBPM)
{
rhythmThread = new Thread(new ThreadStart(RhythmUpdate)); // Initialize new thread
bpm = startingBPM; // < This piece of codde was the source.
rhythmThread.Name = "BeatThread";
rhythmThread.Start(); // Start the thread
}
For now, I'll disable that line of code when testing.

Multiple thread not working correctly in C#

I create parallel process and DataTable dtUser have two rows, it should create two browser:
Parallel.ForEach(dtUser.AsEnumerable(), items =>
OpenBrowser(items["user"].ToString(), items["pass"].ToString()));
Lapsoft_OneDriver browser;
public void OpenBrowser(string username, string password)
{
browser = new Lapsoft_OneDriver(Browsers.Chrome);
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
}
It create two Chrome process but only first process running line code block:
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
The second process only initializes new browser and not do anything.
If I change this line:
browser = new Lapsoft_OneDriver(Browsers.Chrome);
to
var browser = new Lapsoft_OneDriver(Browsers.Chrome);
It's working.
But another method continues to use variable browser to execute other code.
So, I must declare global variable Lapsoft_OneDriver browser out of a function to use in another method use it.
My problem is:
Why using Lapsoft_OneDriver browser; it create two Chrome process but only first process active, it will insert to browser.FindElementById("txtUserName") two values of variable username and second process not do anything?
Updated:
When to change the code, I have any problem.
I will add more code of frmMain_Load:
private void frmMain_Load(object sender, EventArgs e)
{
thread = new LThread();
thread.StartedEvent += new LThread.startDelegate(AllCaseProgram);
numLog = int.Parse(dtSetting.Rows[0]["num_Log"].ToString());
}
int numProcess;
private void AllCaseProgram(object args)
{
try
{
switch (numProcess)
{
case 0:
Parallel.ForEach(dtUser.AsEnumerable(), items => Start(items["user"].ToString(), items["pass"].ToString()));
break;
case 1:
ClickCart();
break;
case 2:
Result();
break;
}
}
catch (Exception ex)
{
if (browser != null)
browser.Cleanup();
numProcess = 0;
AllCaseProgram(null);
}
}
At event of button StartProgram()_Click. I start Thread like: thread.Start();
You said: should be add this function to my program.
public static void Start(string user, string pwd)
{
var test = new frmMain();
test.OpenBrowser(user, pwd);
test.ClickCart();
}
My update question is:
Seem function Start(string user, string pwd) should be change to function AllCaseProgram include all switch case.
And variable numLog in frmMain_Load have values = 3. In function test.ClickCart() I also use this variable but values auto change to 0.
Have any issues with code? Thanks.
And LThread class is:
public class LThread : BackgroundWorker
{
#region Members
public delegate void startDelegate(string ID);
public event startDelegate StartedEvent;
private static int RandNumber(int Low, int High)
{
Random rndNum = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
int rnd = rndNum.Next(Low, High);
return rnd;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
StartedEvent(RandNumber(100,10000).ToString()); //put whatever parameter suits you or nothing
base.OnDoWork(e);
e.Result = e.Argument;
}
BackgroundWorker bwThread;
// Main thread sets this event to stop worker thread:
public Boolean bwIsRun;
int m_time_delay = 10000;
Delegate m_form_method_run;
Delegate m_form_method_stop;
Form m_type_form;
#endregion
#region Functions
public void Start()
{
try
{
bwIsRun = true;
this.RunWorkerAsync();
}
catch { }
}
public void Stop()
{
try
{
bwIsRun = false;
}
catch { }
}
private void StartToListen(object sender, DoWorkEventArgs e)
{
while (true)
{
Thread.Sleep(m_time_delay);
if (bwIsRun == true)
{
m_type_form.Invoke(m_form_method_run);
}
else
{
BackgroundWorker bwAsync = sender as BackgroundWorker;
if (bwAsync.CancellationPending)
{
e.Cancel = true;
return;
}
break;
}
}
}
#endregion
}
You should encapsulate your state for each test run. That way you'll have a class that has the responsibility the start a browser, execute one or more actions, while keeping all the required state belonging to a single run private for just one instance, while you can have a many instances as you like (if resources permit).
// this is NOT a winform, this is a new and seperate class ...
// don't try to mix this with an WinForm, that will fail
public class BrowserTestRunner
{
// only this Test instances uses this browser
Lapsoft_OneDriver browser;
private void OpenBrowser(string username, string password)
{
browser = new Lapsoft_OneDriver(Browsers.Chrome);
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
// you probably want to click on something here
}
// some other test
private void ClickCart()
{
browser.FindElementById("btnCart").Click();
}
// add other actions here
// this starts the test for ONE browser
public static void Start(string user, string pwd)
{
var runner = new BrowserTestRunner();
runner.OpenBrowser(user, pwd);
// wait for stuff, check data, prepare the next steps
// for example
// runner.ClickCart();
// other actons here
}
}
Now you can create as many Test class instances as you like, while each instance of the class manages its own internal state, without interfering with other instances:
Parallel.ForEach(dtUser.AsEnumerable(), items =>
BrowserTestRunner.Start(items["user"].ToString(), items["pass"].ToString()));
If you want to start that from your backgroundworker do:
private void AllCaseProgram(object args)
{
try
{
switch (numProcess)
{
case 0:
Parallel.ForEach(
dtUser.AsEnumerable(),
items => BrowserTestRunner.Start(items["user"].ToString(), items["pass"].ToString()));
break;
case 1:
ClickCart();
break;
case 2:
Result();
break;
}
}
catch (Exception ex)
{
if (browser != null)
browser.Cleanup();
numProcess = 0;
AllCaseProgram(null);
}
}
By all means: don't start the main form again. Just separate your WinForm from the code you use to operate the browser. That does mean that you have to move the code that interacts with the browser to the BrowserTestRunner. Don't try in keeping the logic for your selenium stuff in the WinForm class because that is doomed to fail. As you are already experiencing.
What you got here is sort of a race condition. You got two threads not getting along when handling a single field in the class. Your problem is only that you don't have sufficient space to store all the browser instances you require.
What happens is basically that the first thread enters the method, creates a instance of the chrome browser and stores it in the variable. Then the second thread enters the function and does the same thing. But it also stores the instance in the same variable. Now the first thread continues and goes to a link. But the instance it is working with is already replaced by the second thread. And so on. This may happen with the threads the other way around or the overlapping may happen after more lines where handled. But it is bound to go wrong.
The way to resolve it, is as you noticed to make the variable local by adding a var. This way both threads are working with distinct variables.
Now you said you need the variable in another function. The question is: Do you need both? Do you need only one? Do you need a specific one?
In case you need only one, you just store the variable in the global variable by adding a line like this in your function:
this.browser = browser;
So it would look like this in total:
Lapsoft_OneDriver browser;
public void OpenBrowser(string username, string password)
{
var localBrowser = new Lapsoft_OneDriver(Browsers.Chrome);
localBrowser.GoToUrl(link);
localBrowser.FindElementById("txtUserName").SendKeys(username);
localBrowser.FindElementById("txtpassword").SendKeys(password);
this.browser = localBrowser;
}
I changed the name of the local browser variable, so it gets clearer what variable is used. Do note that either one of the created browsers could end up in the variable.
In case you need a specific one you have to determine if you have the correct one and store the result after this.
If you need both you have to store them in a list. The namespace System.Collections.Concurrent offers lists that can be handled by multiple threads at once.

thread lock object in properties get/set

When using locks, do I need to lock around my get? From my testing I do not need to do so, but I wanted to make sure. Also, how do I format the code I posted so it has the proper schema colors? It is asking me to add more details, but I don't really know what to add- I am moreover asking (from someone more experienced than I) if what I have is correct and will work without throwing cross thread exceptions.
class exam
{
private static readonly exam x = new exam();
private static readonly object lckobj = new object();
private int i;
private int _count;
private exam() { }
public static exam AccessPoint
{
get
{
return x;
}
}
public int myInt
{
get
{
return i;
}
set
{
lock(lckobj)
{
i = value;
}
}
}
public int Count
{
get
{
return _count;
}
set
{
lock(lckobj)
{
_count = value;
}
}
}
}
class myDemo
{
Random r = new Random();
bool b = false;
Thread[] t = new Thread[3];
public myDemo()
{
for(int i=0; i < 3; i++)
{
t[i] = new Thread(new ThreadStart(thread1));
t[i].Start();
}
Thread checks = new Thread(new ThreadStart(checkB));
checks.Start();
}
void checkB()
{
var x = exam.AccessPoint;
while (!b)
{
b = (x.Count >= 10) ? true : false;
Console.WriteLine("\tb:{0}\tCount:{1}", b, x.Count);
Thread.Sleep(100);
}
}
void thread1()
{
var x = exam.AccessPoint;
while (!b)
{
Thread.Sleep(r.Next(500, 1000));
x.myInt = r.Next(1, 10);
x.Count = x.Count + 1;
Console.WriteLine(x.myInt);
}
}
}
Even if you added the lock around the get your code still wouldn't work properly, although there are more possible things that can go wrong if you don't do that.
The following line is problematic in a way that cannot be fixed by locking in Count:
x.Count = x.Count + 1;
Here even if you add locks, it's entirely possible for one thread to read a value, stop before updating, then have another thread read the value, increment the count, and then write it back. That write will be overridden when the first thread continues on. No amount of locking in Count will change that.
Of course, without the lock in Count there is no memory barrier introduced, so reads to that value are allowed to be reading stale values, which can further exacerbate the previous problem.
Reading a value of a variable by multiple threads in the same time is safe.
Writing a value to a variable by multiple threads in the same time is not safe.
Writing a value to a variable by one thread in the same time as one ore more threads are reading from this variable is not safe.
So using the same lock in both setter and getter is required.
Problem described in #Servy answer requires a better solution though. Any flavour of locking mechanism which wraps so called "SELECT FOR UPDATE" (I know this goes for DB but the problem is the same) should be good enough.
You should even reuse the same lock you already have in your code. Make it public since it's readonly and for such situations use it from outside:
lock(exam.lckobj){
exam.myInt = exam.myInt + 1;
}
For integer values use Interlocked.Read and Interlock.Exchange. Very atomic, very thread safe, doesn't carry the weight of a mutex (via lock).

Stop a loop inside a method in C#

Is there any way to stop a running loop inside another method or insert a break statement dynamically in C#?
Thanks
Edit : I want to be able to dynamically intercept the method and insert a break to stop the loop when an event gets triggered in another function.I have several instances of the class and I want to stop the loop in each instance whenever required and manage all the instances. Consider multiple instances to be in a generic list
Example :
List<myclass> objlist=new List<myclass>();
foreach(myclass obj in objlist)
{
obj.loopingfunction().BreakLoop //or something like this (assuming that the loopingfunction is already called)
}
I need this because I want to break the loop once the user stores some huge amount of data.When the user imports the data,I get a event fired. But I cannot keep checking the database from multiple instances since it screws up sqlserver.
This is in an ASP.Net application.
If the whole thing is running in a single thread, it wouldn't make any sense. If the loop is running, then nothing else is running at the same time. If you're running a loop on another thread and the controlling method on another thread, you can either abort the loop thread completely or check a flag inside the loop to decide whether or not you should break and set the flag appropriately in the controlling method.
Update: make that function return a boolean value indicating whether you should break and use it in an "if" statement:
if (myFunctionShouldBreakLoop()) break;
Another option would be to raise a CancelEventArgs during every iteration of the loop. Probably not the most efficient, but another option nonetheless:
private void SomeMethod()
{
for (int i = 0; i <= 100000; i++)
{
Console.WriteLine(i);
if (LoopIncrement != null)
{
CancelEventArgs args = new CancelEventArgs();
LoopIncrement(null, args);
if (args.Cancel)
{
break;
}
}
}
And then elsewhere:
myObj.LoopIncrement += MyHandler;
private void MyHandler(object sender, CancelEventArgs e)
{
if(someCondition)
{
e.Cancel = true;
}
}
This way you can somewhat control the loop from outside....
Have the condition in a locked property.
private Boolean BreakCondition
{
get { lock(_LockObject) { return _BreakCondition; } }
set { lock(_LockObject) { _BreakCondition = value; } }
}
private Boolean _BreakCondition = false;
private Object _LockObject = new Object();
if (this.BreakCondition)
{
break;
}
How about using iterators, and yield magic to solve the problem.
Here is an article on infinite lists that might be useful
http://www.codethinked.com/post/2009/02/04/Infinite-Lists-With-C-Yield.aspx
class Program
{
static void Main(string[] args)
{
Predicate<int> when = i => i > 100 && Console.ReadKey().KeyChar.ToString() == "0";
foreach(var i in Numbers().BreakOn(when))
{
Console.WriteLine(i);
}
Console.ReadLine();
}
private static IEnumerable<int> Numbers()
{
var i = 0;
while(true)
{
yield return i++;
}
}
}
public static class Util
{
public static IEnumerable<int> BreakOn(this IEnumerable<int> sequence, Predicate<int> when)
{
foreach(int i in sequence)
{
if(when(i))
{
yield break;
}
yield return i;
}
}
}
I think you can use flag
bool stop = false;
for(int i=0;i<num;i++)
{
if(stop) break;
}
The short answer is: no. If you don't control the code, then you can't cause the loop to terminate.
If you do control the code, you could build in some sort of cooperation, but it sounds messy. Maybe you can elaborate on why?

Categories

Resources