Stop a loop inside a method in C# - 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?

Related

Waiting for a result before continuing and without blocking UI [duplicate]

This question already has answers here:
Is async always asynchronous in C#? [duplicate]
(1 answer)
Do you have to put Task.Run in a method to make it async?
(3 answers)
async method in C# not asynchronous?
(3 answers)
Closed 5 years ago.
I have a TextBox with a TextChanged event that calls a custom event if the text of the textbox represents an existing file. In this event, there is a call to an outside dll that does some processing on the File, which can take upwards of a minute to finish. There is also some post-processing I do, dependent on what result this method returns to me. Currently, this is blocking my UI, which is highly undesirable.
There are essentially 2 "options"/scenarios I see.
Within the custom event, somehow wait for the dll call to finish, before continuing the event, while also keeping the UI free. This seems like the simplest idea from my multithreading-untrained self, but it also conceptually throws red flags at me: Is this even possible given that the custom event itself (called from TextChanged) is on the UI thread?
Throw the entire custom event into it's own thread using Task.Run(). Downside here is that apart from the dll method call, there is quite a good amount of UI elements that are affected by getters/setters after the long method. I could write alternated getters/setters based on the appropriate InvokeRequired, but if there is a more correct way to do this, I'd rather take that approach.
I made a much shorter (although contrived) example project, which shows essentially what I'm after, using option 2 from above:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
comboBox1.Items.Add("Select One...");
comboBox1.Items.Add("Item 1");
comboBox1.Items.Add("Item 2");
Value = 0;
}
public string SetMessage
{
set
{
if (lblInfo.InvokeRequired)
lblInfo.BeginInvoke((MethodInvoker)delegate () { lblInfo.Text = Important ? value + "!" : value; });
else
lblInfo.Text = Important ? value + "!" : value;
}
}
public bool Important
{
get
{
return chkImportant.Checked;
}
set
{
if (chkImportant.InvokeRequired)
chkImportant.BeginInvoke((MethodInvoker) delegate() { chkImportant.Checked = value; });
else
chkImportant.Checked = value;
}
}
public SomeValue Value
{
get
{
if (comboBox1.InvokeRequired)
{
SomeValue v = (SomeValue)comboBox1.Invoke(new Func<SomeValue>(() => SomeValue.Bar));
return v;
}
else
{
switch (comboBox1.SelectedIndex)
{
case 1:
return SomeValue.Foo;
case 2:
return SomeValue.Bar;
default:
return SomeValue.Nothing;
}
}
}
set
{
if (comboBox1.InvokeRequired)
{
comboBox1.BeginInvoke((MethodInvoker)delegate ()
{
switch (value)
{
case SomeValue.Nothing:
comboBox1.SelectedIndex = 0;
break;
case SomeValue.Foo:
comboBox1.SelectedIndex = 1;
break;
case SomeValue.Bar:
comboBox1.SelectedIndex = 2;
break;
}
});
}
else
{
switch (value)
{
case SomeValue.Nothing:
comboBox1.SelectedIndex = 0;
break;
case SomeValue.Foo:
comboBox1.SelectedIndex = 1;
break;
case SomeValue.Bar:
comboBox1.SelectedIndex = 2;
break;
}
}
}
}
private void CustomEvent(object sender, EventArgs e)
{
if (!Important)
Important = true;
SetMessage = "Doing some stuff";
if (Value == SomeValue.Foo)
Debug.WriteLine("Foo selected");
//I don't want to continue until a result is returned,
//but I don't want to block UI either.
if (ReturnsTrueEventually())
{
Debug.WriteLine("True!");
}
Important = false;
SetMessage = "Finished.";
}
public bool ReturnsTrueEventually()
{
//Simulates some long running method call in a dll.
//In reality, I would interpret an integer and return
//an appropriate T/F value based on it.
Thread.Sleep(5000);
return true;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
//Do I *need* to multithread the whole thing?
Task.Run(() => CustomEvent(this, new EventArgs()));
}
}
public enum SomeValue
{
Nothing = 0,
Foo = 100,
Bar = 200
}
Note: I'm not asking for code review on my option 2 code. Rather, I'm asking if option 2 is necessary to accomplish, since that option causes me to change a considerably larger portion of code, given that it's only 1 method within it holding up the entire process.
I also realize I can simplify some of the code in these properties to prevent replication. For the sake of demonstrating to myself and debugging, I am holding off on that at this time.
Here is what I had related to option 1 (left out duplicate code and the getters/setters without their invokes):
private async void CustomEvent(object sender, EventArgs e)
{
if (!Important)
Important = true;
SetMessage = "Doing some stuff";
if (Value == SomeValue.Foo)
Debug.WriteLine("Foo selected");
//I don't want to continue until a result is returned,
//but I don't want to block UI either.
if (await ReturnsTrueEventually())
{
Debug.WriteLine("True!");
}
Important = false;
SetMessage = "Finished.";
}
public async Task<bool> ReturnsTrueEventually()
{
//Simulates some long running method call in a dll.
//In reality, I would interpret an integer and
//return an appropriate T/F value based on it.
Thread.Sleep(5000);
return true;
}
This is basically what you want. I'm violating a couple best-practices here, but just showing it's not that complicated. One thing to keep in mind is that the user can now click this button multiple times in a row. You might consider disabling it before processing. Or you can do a Monitor.TryEnter() to make sure it's not already running.
private async void buttonProcess_Click(object sender, RoutedEventArgs e)
{
textBlockStatus.Text = "Processing...";
bool processed = await Task.Run(() => SlowRunningTask());
}
private bool SlowRunningTask()
{
Thread.Sleep(5000);
return true;
}

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.

C# MultiThreading: pool of calculators

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.

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).

Is it possible to invoke functions used to create parameters for a method from inside that method? (C#)

This is a bit hard to explain, but I'm hoping this example will clear it up.
Say I have some function call Visible:
public bool Visible(/* Some page element */)
{
// Checks if something on a webpage is visible. Returns a "true" is yes, and "false" if not
}
Is it possible to some how wait for this function to return true? What I've written out so far looks like this:
public void WaitUntil(/*function returning bool*/ isTrue)
{
for (int second = 0; ; second++)
{
if (second >= 12)
{
/* Thow exception */
}
else
{
if (isTrue /*calls the isTrue function with given parameters*/)
{
return;
}
}
}
}
Such that these two method could be used together like:
WaitUntil(Visible(/* Some page element */));
to wait until a page element is visible... Is this possible?
Here is how to do it (although you should consider using events as this kind of "waiting" is strongly discouraged)
/*Important Note: This is ugly, error prone
and causes eye itchiness to veteran programmers*/
public void WaitUntil(Func<bool> func)
{
DateTime start = DateTime.Now;
while(DateTime.Now - start < TimeSpan.FromSeconds(12))
{
if (func())
{
return;
}
Thread.Sleep(100);
}
/* Thow exception */
}
//Call
WaitUntil(() => Visible(/* Some page element*/));

Categories

Resources