Stop a function

  • Thread starter Thread starter cody
  • Start date Start date
C

cody

I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


You need to run that method in a separate Thread. If you press the button,
set a flag which you test in the method and return in this case.
 
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...
 
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is generated yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,
 
Scenario #1 is preferable to spawning a thread, which would be difficult to
manage, test, debug, etc.

Brad Williams


Ignacio Machin ( .NET/ C# MVP ) said:
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is generated yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Ricardo said:
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...
 
Hi,

It's as long as the operation to be performed is not lengthy, if it's the
UI will hang until the call to DoEvents() .


Cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Brad Williams said:
Scenario #1 is preferable to spawning a thread, which would be difficult to
manage, test, debug, etc.

Brad Williams


"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote
in message news:[email protected]...
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is
generated
yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Ricardo said:
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...
 
Ignacio Machin ( .NET/ C# MVP ) said:
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is generated yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Ricardo said:
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...

Hi.

The use of DoEvent is a very risky practice. Indeed, any event can occur
during the call of doevent. It might change some input you are dealing with
in your generateRandom method.
You must be very cautious of not encounter some incoherences.
Althought it may look a little bit more complex, you should definitely use a
worker thread. It is much easier to control.

Fred
 
Iceman said:
The use of DoEvent is a very risky practice.

This is exactly how we handled this in Windows 3.1, and the code was ugly
but actually much less error prone than trying to herd threads.
Multithreaded programming is harder than most people realize, unfortunately.

Brad Williams
 
could you send the code of scenario 2 to my e-mail:
(e-mail address removed)

bye...


Ignacio Machin ( .NET/ C# MVP ) said:
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is generated yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Ricardo said:
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...
 
The UI is hanging, the scenario 1 not work...

Ignacio Machin ( .NET/ C# MVP ) said:
Hi,

It's as long as the operation to be performed is not lengthy, if it's the
UI will hang until the call to DoEvents() .


Cheers,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Brad Williams said:
Scenario #1 is preferable to spawning a thread, which would be difficult to
manage, test, debug, etc.

Brad Williams


"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote
in message news:[email protected]...
use
a generated listbox
when
that
is
running???


[]s...
 
Brad Williams said:
This is exactly how we handled this in Windows 3.1, and the code was ugly
but actually much less error prone than trying to herd threads.
Multithreaded programming is harder than most people realize, unfortunately.

Sure - but calling DoEvents is also riskier than most people realise, I
believe.

Sooner or later, pretty much every serious .NET programmer is going to
*have* to start to understand threading. Why not encourage people to
grab the bull by the horns and learn how to do it properly now? I don't
think encouraging them to use what is essentially a nasty workaround
hack is a good idea.

Must get round to finishing my article on multi-threading soon...
 
Hi Ricardo,

I posted it here for it to get archived.
A have a suggestiong though, maybe is better for you to use a textbox to
indicate how many numbers the user want, if you depend of the user clicking
a Stop button it will be dependant of the speed of the machine.

PD:
this is only togive you an idea of how to do it, it will runs fine
although.

Cheers,
--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation


public delegate void InsertNumberHandler( int numberToInsert);

InsertNumberHandler onnewnumber;
Thread workingThread;
bool keepgoing = true;

Random random = new Random( DateTime.Now.Second );

public Form1()
{
onnewnumber = new InsertNumberHandler( NewNumber);
workingThread = new Thread( new ThreadStart( NumberGenerator));
}

void NewNumber( int i )
{
this.comboBox1.Items.Add( i);
}
void NumberGenerator()
{
while( keepgoing)
{
int i = random.Next();
this.comboBox1.Invoke ( onnewnumber, new object[] { i} );
Thread.Sleep(1000);
}

}


private void StartBTN_Click(object sender, System.EventArgs e)
{
if ( workingThread.ThreadState == ThreadState.Unstarted )
workingThread.Start();
else
workingThread.Resume();
}

private void StopBTN_Click(object sender, System.EventArgs e)
{
workingThread.Suspend();
}
// Terminate the working thread
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
keepgoing = false;
}


Ricardo said:
could you send the code of scenario 2 to my e-mail:
(e-mail address removed)

bye...


"Ignacio Machin ( .NET/ C# MVP )" <ignacio.machin AT dot.state.fl.us> wrote
in message news:[email protected]...
Hi Ricardo,

There are a few ways of doing it , it all depend of how/where you run the
random generator, I will show you two escenarios
1- gen. runs on the same thread.

while you are generating numbers , between number generation you call
Application.DoEvents() this process the events queries, you can then use a
Stop button that set a flag to false, before the next number is
generated
yo
check for this flag, like this:

bool generate = true;
void generaterandom( object sender, EventArgs e )
{
while ( generate)
{
// generate it and update the UI
Application.DoEvents();
}

}
void Stop_OnClick( object sender, EventArgs e )
{
generate = false;
}

2- run the generator on another thread and then the Stop button can pause
the thread execution, remember that if you use this approach you have to
make sure that the call to update the interface be called in the main thread
using Control.Invoke

Pd: I will not post code for this as its a little more complex, just drop
me a note if you need it

HTH,

--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation

Ricardo said:
I made a program that generate random numbers and put it in a listbox when
the user click go.
The problem is: how can i made a button stop, to stop the method that is
running???


[]s...
 
<"Ignacio Machin \( .NET/ C# MVP \)" <ignacio.machin AT
dot.state.fl.us> said:
I posted it here for it to get archived.

Unfortunately it'll be archived including its bug then :(

Your code uses a non-volatile boolean variable (keepgoing), and updates
and reads it without any locking or memory barriers being involved.
It's therefore not guaranteed that the reading thread will ever see the
value changed in another thread.

In practice this won't actually be a problem, as the JIT *isn't* going
to cache the value, but it theoretically could - the code is
theoretically broken.

The simple way to fix it is to have a reference which is locked every
time you touch the shared data (the boolean). The easiest way of doing
that is to use properties to access the data and put locks in the
property:

bool keepGoing;
object keepGoingLock = new object();

public bool KeepGoing
{
get
{
lock (keepGoingLock)
{
return keepGoing;
}
}
set
{
lock (keepGoingLock)
{
keepGoing = value;
}
}
}
 
Hi jon,

You are as always right :)

It should be locked

Thanks for point it.

Cheers,
 
i made a stop button that turn the bool to false, and made calls to doevents
in some critical parts of the method, the problem is that the UI hang and i
can't press the button.

And there's a textbox wich the number the user want...


Ignacio Machin ( .NET/ C# MVP ) said:
Hi jon,

You are as always right :)

It should be locked

Thanks for point it.

Cheers,
 
Sure - but calling DoEvents is also riskier than most people realise, I
believe.

Sooner or later, pretty much every serious .NET programmer is going to
*have* to start to understand threading. Why not encourage people to
grab the bull by the horns and learn how to do it properly now? I don't
think encouraging them to use what is essentially a nasty workaround
hack is a good idea.


So what exactly is risky with DoEvents()? The worst thing I can imagine is
that the UI has slow response times, thats all.
With threads you have much more problems and things to care about.
 
Your code uses a non-volatile boolean variable (keepgoing), and updates
and reads it without any locking or memory barriers being involved.
It's therefore not guaranteed that the reading thread will ever see the
value changed in another thread.

In practice this won't actually be a problem, as the JIT *isn't* going
to cache the value, but it theoretically could - the code is
theoretically broken.

The simple way to fix it is to have a reference which is locked every
time you touch the shared data (the boolean). The easiest way of doing
that is to use properties to access the data and put locks in the
property:

bool keepGoing;
object keepGoingLock = new object();

public bool KeepGoing
{
get
{
lock (keepGoingLock)
{
return keepGoing;
}
}
set
{
lock (keepGoingLock)
{
keepGoing = value;
}
}
}


Nothing stops the Jit from inlining this property and nobody guarantees you
that keepGoing is reloaded from memory each time you call it, at least in
theory.
I also do not understand what locking in this case is good for since you
have only one operation in the method body.

The simplest and safest solution is a volatile variable.
 
Ricardo said:
i made a stop button that turn the bool to false, and made calls to doevents
in some critical parts of the method, the problem is that the UI hang and i
can't press the button.

So don't call DoEvents - do your processing in a different thread.
 
cody said:
So what exactly is risky with DoEvents()? The worst thing I can imagine is
that the UI has slow response times, thats all.

Your stack gets deeper and deeper the more things which go on within
your DoEvents, possibly leading to a StackOverflow which is solely due
to simulating multiple threads within a single thread.

If you make *any* blocking calls, you are tying up your UI for a
potentially *very* long time - not just slow response times, but a
completely *unresponsive* UI.

You still have to work out which bits of code must execute in a sort of
"transactional" way without calling DoEvents again, in case the other
events will modify data you're relying on not changing.

See "On COM, pumping and the CLR" in
http://mikedimmick.blogspot.com/2004_02_01_mikedimmick_archive.html
for some another example.

Fundamentally the usual problem is wanting to do more than one thing at
a time - and that's precisely what threads are designed to do.
With threads you have much more problems and things to care about.

Sure - but there are good solutions to all of them. As I said, sooner
or later, all serious .NET developers are going to understand threading
- so why not learn the "proper" way of doing things once, rather than
first learning the hacky not-suitable-for-all-situations way (along
with the rules as to what makes a situation suitable or not) and then
having to learn threading anyway?
 
cody said:
Nothing stops the Jit from inlining this property
Immaterial.

and nobody guarantees you
that keepGoing is reloaded from memory each time you call it, at least in
theory.

Yes, the spec guarantees it. From section 12.6.5 of the ECMA CLR spec,
partition 1:

<quote>
Acquiring a lock (System.Threading.Monitor.Enter or entering a
synchronized method) shall implicitly perform a volatile read
operation, and releasing a lock (System.Threading.Monitor.Exit or
leaving a synchronized method) shall implicitly perform a volatile
write operation.
</quote>

Those volatile reads and writes then assure acquire/release semantics.
I also do not understand what locking in this case is good for since you
have only one operation in the method body.

The simplest and safest solution is a volatile variable.

Locks are just as safe, and given that you'll need to use them at
*some* point, it makes sense (to me) to only learn one method of
thread-safety, rather than working out when to use a volatile and when
to use a lock.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top