I have a C# method, if a condition is not met I want to re-run the Main() method.
There are a few posts saying use loops to do this. GoTo would also work - but don't use it. Or restart the application.
No one has given a clear newbie-level explanation about the loops.
C# example:
public static void Method3(int userChoice){
if(userChoice == 1){
Console.WriteLine("do this");
}
else{
Main(); // How to run the main program again from the start ?
}
}
public static void Main(string[] args)
{
Method1();
int userChoice = Method2();
Method3(userChoice); // I want Method3 to go back to Method1() if the else statement is met.
}
In python this is real easy - you just call Main() from the function.
You can have Method3() return a bool so the Main() method knows whether to try again.
public static bool Method3(int userChoice)
{
if (userChoice == 1)
{
Console.WriteLine("do this");
return false;
}
return true;
}
public static void Main(string[] args)
{
bool tryAgain;
do
{
Method1();
int userChoice = Method2();
tryAgain = Method3(userChoice);
} while (tryAgain);
}
Simply calling Main() again instead of looping is another approach, but has some disadvantages.
You'll have to come up with the args argument somehow. Maybe it's just an empty array in your case.
It's a recursive call and affects the stack trace. After so many recursive calls, your application will crash.
It decreases maintainability. You'll have to remember in the future if you want to add anything to the top of the Main() method that you're calling it from somewhere. It lends itself to the introduction of potentially hard-to-diagnose bugs. Using the loop approach encapsulates the behavior. From just looking at Main(), it's obvious that Method3() might cause another loop.
First of all, yes, you can call Main. Please note that in your example you are missing the args parameters (which would have the command line arguments). Besides that, also know that Main returns, and then execution continues after where you called it. Also, you would very likely end up with a stack overflow. If I recall correctly modern versions of the JIT can optimize tail recursion, yet I do not believe they do for this particular case.
About that newbie-level explanation of a loop... this is an infinite loop, it will run forever:
while(true)
{
// ...
}
You can exit the loop with break
while(true)
{
// ...
if (something)
{
break;
}
// ...
}
Or you can change that true for a conditional:
while(!something)
{
// ...
}
The idea would be to wrap Main in a loop, so that it would continue to run until a condition is met. You could have another method and call it in the loop, for example:
public static bool Execute()
{
if (something)
{
// do whatever
return true;
}
return false;
}
public static void Main(string[] args)
{
while (!Execute())
{
// Empty
}
}
There are, of course, other kinds of loops aside from the while loop, they are the do...while loop, for loop, and foreach loop.
Goto would work? Arguably. The idea is that you can use goto to control the flow of execution to back in the method. That is:
label:
// ...
goto label;
The above code is an infinite loop. You can, of course, introduce a condition:
label:
// ...
if (!something)
{
goto label;
}
// ...
The while can do – sometimes with the help of a variable – whatever you can do with goto, and it is usually easier to read and less error prone.
Restarting the process is a bit more tricky, you need to use Process.Start to run your own executable. See What is the best way to get the executing exe's path in .NET?.
So it's not really hard to do but you can just use a while loop.
C#:
public static void Main(string[] args)
{
while(true)
{
Method1();
int userChoice = Method2();
Method3(userChoice);
}
}
That would give you what you want and if you want to exit you just put
break;
Related
I'm trying to simulate (very basic & simple) OS process manager subsystem, I have three "processes" (workers) writing something to console (this is an example):
public class Message
{
public Message() { }
public void Show()
{
while (true)
{
Console.WriteLine("Something");
Thread.Sleep(100);
}
}
}
Each worker is supposed to be run on a different thread. That's how I do it now:
I have a Process class which constructor takes Action delegate and starts a thread from it and suspends it.
public class Process
{
Thread thrd;
Action act;
public Process(Action act)
{
this.act = act;
thrd = new Thread(new ThreadStart(this.act));
thrd.Start();
thrd.Suspend();
}
public void Suspend()
{
thrd.Suspend();
}
public void Resume()
{
thrd.Resume();
}
}
In that state it waits before my scheduler resumes it, gives it a time slice to run, then suspends it again.
public void Scheduler()
{
while (true)
{
//ProcessQueue is just FIFO queue for processes
//MainQueue is FIFO queue for ProcessQueue's
ProcessQueue currentQueue = mainQueue.Dequeue();
int count = currentQueue.Count;
if (currentQueue.Count > 0)
{
while (count > 0)
{
Process currentProcess = currentQueue.GetNext();
currentProcess.Resume();
//this is the time slice given to the process
Thread.Sleep(1000);
currentProcess.Suspend();
Console.WriteLine();
currentQueue.Add(currentProcess);
count--;
}
}
mainQueue.Enqueue(currentQueue);
}
}
The problem is that it doesn't work consistently. It even doesn't work at all in this state, i have to add Thread.Sleep() before WriteLine in Show() method of the worker, like this.
public void Show()
{
while (true)
{
Thread.Sleep(100); //Without this line code doesn't work
Console.WriteLine("Something");
Thread.Sleep(100);
}
}
I've been trying to use ManualResetEvent instead of suspend/resume, it works, but since that event is shared, all threads relying on it wake up simultaneously, while I need only one specific thread to be active at one time.
If some could help me figure out how to pause/resume task/thread normally, that'd be great.
What I'm doing is trying to simulate simple preemptive multitasking.
Thanks.
Thread.Suspend is evil. It is about as evil as Thread.Abort. Almost no code is safe in the presence of being paused at arbitrary, unpredictable locations. It might hold a lock that causes other threads to pause as well. You quickly run into deadlocks or unpredictable stalls in other parts of the system.
Imagine you were accidentally pausing the static constructor of string. Now all code that wants to use a string is halted as well. Regex internally uses a locked cache. If you pause while this lock is taken all Regex related code might pause. These are just two egregious examples.
Probably, suspending some code deep inside the Console class is having unintended consequences.
I'm not sure what to recommend to you. This seems to be an academic exercise so thankfully this is not a production problem for you. User-mode waiting and cancellation must be cooperative in practice.
I manage to solve this problem using static class with array of ManualResetEvent's, where each process is identified by it's unique ID. But I think it's pretty dirty way to do it. I'm open to other ways of accomplishing this.
UPD: added locks to guarantee thread safety
public sealed class ControlEvent
{
private static ManualResetEvent[] control = new ManualResetEvent[100];
private static readonly object _locker = new object();
private ControlEvent() { }
public static object Locker
{
get
{
return _locker;
}
}
public static void Set(int PID)
{
control[PID].Set();
}
public static void Reset(int PID)
{
control[PID].Reset();
}
public static ManualResetEvent Init(int PID)
{
control[PID] = new ManualResetEvent(false);
return control[PID];
}
}
In worker class
public class RandomNumber
{
static Random R = new Random();
ManualResetEvent evt;
public ManualResetEvent Event
{
get
{
return evt;
}
set
{
evt = value;
}
}
public void Show()
{
while (true)
{
evt.WaitOne();
lock (ControlEvent.Locker)
{
Console.WriteLine("Random number: " + R.Next(1000));
}
Thread.Sleep(100);
}
}
}
At Process creation event
RandomNumber R = new RandomNumber();
Process proc = new Process(new Action(R.Show));
R.Event = ControlEvent.Init(proc.PID);
And, finally, in scheduler
public void Scheduler()
{
while (true)
{
ProcessQueue currentQueue = mainQueue.Dequeue();
int count = currentQueue.Count;
if (currentQueue.Count > 0)
{
while (count > 0)
{
Process currentProcess = currentQueue.GetNext();
//this wakes the thread
ControlEvent.Set(currentProcess.PID);
Thread.Sleep(quant);
//this makes it wait again
ControlEvent.Reset(currentProcess.PID);
currentQueue.Add(currentProcess);
count--;
}
}
mainQueue.Enqueue(currentQueue);
}
}
The single best advice I can give with regard to Suspend() and Resume(): Don't use it. You are doing it wrong™.
Whenever you feel a temptation to use Suspend() and Resume() pairs to control your threads, you should step back immediately and ask yourself, what you are doing here. I understand, that programmers tend to think of the execution of code paths as of something that must be controlled, like some dumb zombie worker that needs permament command and control. That's probably a function of the stuff learned about computers in school and university: Computers do only what you tell them.
Ladies & Gentlemen, here's the bad news: If you are doing it that way, this is called "micro management", and some even would call it "control freak thinking".
Instead, I would strongly encorage you to think about it in a different way. Try to think of your threads as intelligent entities, that do no harm and the only thing they want is to be fed with enough work. They just need a little guidance, that's all. You may place a container full of work just in front of them (work task queue) and have them pulling the tasks from that container themselves, as soon as the finished their previous task. When the container is empty, all tasks are processed and there's nothing left to do, they are allowed to fall asleep and WaitFor(alarm) which will be signaled whenever new tasks arrive.
So instead of command-and-controlling a herd of dumb zombie slaves that can't do anything right without you cracking the whip behind them, you deliberately guide a team of intelligent co-workers and just let it happen. That's the way a scalable architecture is built. You don't have to be a control freak, just have a little faith in your own code.
Of course, as always, there are exceptions to that rule. But there aren't that many, and I would recommend to start with the work hypothesis, that your code is probably the rule, rather than the exception.
In the following C# code, t1 always(for the times I tried) finishes.
class MainClass
{
static void DoExperiment ()
{
int value = 0;
Thread t1 = new Thread (() => {
Console.WriteLine ("T one is running now");
while (value == 0) {
//do nothing
}
Console.WriteLine ("T one is done now");
});
Thread t2 = new Thread (() => {
Console.WriteLine ("T two is running now");
Thread.Sleep (1000);
value = 1;
Console.WriteLine ("T two changed value to 1");
Console.WriteLine ("T two is done now");
});
t1.Start ();
t2.Start ();
t1.Join ();
t1.Join ();
}
public static void Main (string[] args)
{
for (int i=0; i<10; i++) {
DoExperiment ();
Console.WriteLine ("------------------------");
}
}
}
But in the Java code which is very similar, t1 never(for the times I tried) exits:
public class MainClass {
static class Experiment {
private int value = 0;
public void doExperiment() throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("T one is running now");
while (value == 0) {
//do nothing
}
System.out.println("T one is done now");
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("T two is running now");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
value = 1;
System.out.println("T two changed value to 1");
System.out.println("T two is done now");
}
}
);
t1.start();
t2.start();
t1.join();
t1.join();
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Experiment().doExperiment();
System.out.println("------------------------");
}
}
}
Why is that?
I'm not sure how it happens in C#, but what happens in Java is JVM optimization. The value of value does not change inside the while loop and the JVM recognises it and just skip the test and change your bite code to something like this:
while (true) {
// do nothing
}
In order to fix this in java you need to declare value as volatile:
private volatile int value = 0;
This will make the JVM to not optimise this while loop and check the for the actual value of value at the start of each iteration.
There are a couple of things here.
Firstly, when you do:
t1.Start ();
t2.Start ();
You're asking the operating system to schedule the threads for runnings. It's possible that t2 will start first. In fact it may even finish before t1 is ever scheduled to run.
However, there is a memory model issue here. Your threads may run on different cores. It's possible that value is sitting in the CPU cache of each core, or is stored in a register on each core, and when you read/write to value you are writing to the cache value. There's no requirement for the language runtime to flush the writes to value back to main memory, and there's no requirement for it to read the value back from main memory each time.
If you want to access a shared variable then it's your responsibility to tell the runtime that the variable is shared, and that it must read/write from main memory and/or flush the CPU cache. This is typically done with lock, Interlocked or synchronized constructs in C# and Java. If you surround access to value with a lock (in C#) or synchronized (in Java) then you should see consistent results.
The reason things behave differently without locking is that each language defines a memory model, and these models are different. Without going into the specifics, C# on x86 writes back to main memory more than the Java memory model does. This is why you're seeing different outcomes.
Edit: For more information on the C# side of things take a look at Chapter 4 of Threading in C# by Joseph Albahari.
Why can't I use a break; statement in a while loop, whilst in an anonymous method?
I was working on the piece of code (below), when I got this error: "Control cannot leave the body of an anonymous method or lambda expression".
Thankfully I can solve the problem by using return; instead, but I'd still like to know why I can't use break;. To me, the main difference between the two statements, was that return; exits a method, and break; exits the further-most nested loop.
My code,
while (someCondition)
{
System.Threading.Thread.Sleep(500);
Application.Current.Dispatcher.Invoke(new Action(() =>
{
if (someOtherCondition)
{
// Do stuff...
}
else
{
if (anotherCondition)
{
break;
}
// Do something else...
}
}));
}
Rewriting the code helps to explain why:
while (someCondition)
{
System.Threading.Thread.Sleep(500);
Application.Current.Dispatcher.Invoke(MyMethod);
}
private void MyMethod()
{
if (someOtherCondition)
{
// Do stuff...
}
else
{
if (anotherCondition)
{
break;
}
// Do something else...
}
}
You are breaking inside a function that has no loop. The loop exists in another method. So return needs to be called instead, as you found out. Just because you are using an annonymous method, it's still a separate method to the one containing the while loop.
For the same reason you can't do this:
while(1)
{
method1();
}
void method1()
{
break;
}
Even if your anonymous method is written in the same function as your while loop, it can still be called from somewhere where there isn't a while loop around.
break; cannot be used to exit methods, instead you need a return. And while inside a method your scope is limited to that method because it could have been called from anywhere. While inside the method there is no information on the calling scope and the code therefore does not know if there is a loop to break out of. So a method scope is different than the scope of an if-statement.
Return takes you out of a method or a function but break gets you out of the loop or an iteration.
This is the main diff.
// This is Oki
public void Do()
{
for (int i = 0; i < 10; i++)
{
break;
}
}
// This is a compiler error
public void Do()
{
break;
}
You can change condition of while:
while (someCondition)
{
System.Threading.Thread.Sleep(500);
Application.Current.Dispatcher.Invoke(new Action(() =>
{
if (someOtherCondition)
{
// Do stuff...
}
else
{
if (anotherCondition)
{
//break;
someCondition = false;
return;
}
// Do something else...
}
}));
if (!someCondition)
break;
}
Not really language specific, but I have this in C#:
public static void StartJob() {
ThreadPool.QueueUserWorkItem(s => {
if (Monitor.TryEnter(_lock)) {
ProcessRows();
Monitor.Exit(_lock);
}
}
);
ProcessRows() processes and removes rows in a database until all rows are removed. At program launch and whenever a row is added to the database elsewhere in the program, StartJob is called, to ensure all rows are processed without blocking the program. Now if a row is added at exactly the same time as StartJob is about to release the lock, it will not be processed.
How do I ensure that all rows are processed? I prefer not to have ProcessRows() run unless rows are added.
Don't lock around the method; lock within the method using a flag that says whether you're running or not.
One implementation might look like the code below - in this case I've moved all the logic into ProcessRows and made the method return immediately if it's already running.
public static bool _isRunning = false;
public static void StartJob()
{
ThreadPool.QueueUserWorkItem(s => { ProcessRows(); })
}
public static void ProcessRows()
{
Monitor.Enter(_lock);
if (_isRunning)
{
Monitor.Exit(_lock);
return;
}
_isRunning = true;
while (rowsToProcess)
{
Monitor.Exit(_lock);;
// ... do your stuff
Monitor.Enter(_lock);
}
_isRunning = false;
Monitor.Exit(_lock);
}
With this structure, it's impossible for the while loop to complete without setting _isRunning = false - if this weren't the case, there would be a race condition if the loop completed just as another instance of the method started. Equally, when the method is called, it will always enter the loop and set _isRunning = true before another instance gets a chance to execute.
In process of developing I often face with the next problem: if some method is already executed by one thread - method is must not be executed by another thread. Another thread must do nothing - simple exit from method, beacuse of it I can't use "lock". Usually, I solve this problem like that:
private bool _isSomeMethodExecuted = false;
public void SomeMethod ()
{
if (!this._isSomeMethodExecuted) //check if method is already executed
{
this._isSomeMethodExecuted = true;
//Main code of method
this._isSomeMethodExecuted = false;
}
}
But this code is not thread-safe: if one thread execute condition statement but It be stopped before set flag in true and another thread can execute condition - then both threads are inside method code.
Is there any thread-safe replace for it?
the following is thread-safe and does not block if the method is already executing - even if it is alreasy executing on the same thread... which provides protection from reentrancy for all scenarios.
private long _isSomeMethodExecuted = 0;
public void SomeMethod ()
{
if (Interlocked.Increment (ref this._isSomeMethodExecuted) == 1) //check if method is already executed
{
//Main code of method
}
Interlocked.Decrement (ref this._isSomeMethodExecuted);
}
For refrences see http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx
Monitor does this job for you, but the lock is thread-wide (and therefore open for recursive calls!). The lock statement uses a Monitor too (using the blocking Enter method), but you may work with the TryEnter method instead:
if(Monitor.TryEnter(myLockObject))
{
try
{
DoSomething(); // main code
}
finally
{
Monitor.Exit(myLockObject);
}
}
TryEnter does not block but returns a bool indicating whether the lock was successfully acquired or not.
If you want recursive calls not to enter the main code block again, you should use a semaphore instead. Semaphores use counters instead of locking objects, so you cannot reenter even from the same thread:
class Program
{
private static Semaphore sem = new Semaphore(1, 1);
static void Main(string[] args)
{
MyMethod();
MyMethod();
}
private static void MyMethod()
{
if(sem.WaitOne(0))
{
try
{
Console.WriteLine("Entered.");
MyMethod(); // recursive calls won't re-enter
}
finally
{
sem.Release();
}
}
else
{
Console.WriteLine("Not entered.");
}
}
}