how to create a thread - c#

when I click button1 should print A s but when I click button2 need to stop thread1 and need to start thread2, what is the wrong in here please help me
private void button1_Click(object sender, EventArgs e)
{
if (thread2.IsAlive)
{
thread2.Suspend();
}
thread1 = new Thread(threadOne);
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
if (thread1.IsAlive)
{
thread1.Suspend();
}
thread2 = new Thread(threadTwo);
thread2.Start();
}
private void threadOne() {
for (int i=0; i < 20; i++ )
{
Console.Write("A");
Thread.Sleep(500);
}
}
private void threadTwo()
{
for (int i = 0; i < 20; i++)
{
Console.Write("B");
Thread.Sleep(500);
}
}

There's quite a lot wrong, as the other posters have correctly pointed out. I would add this:
1) Most threads in commercial-grade software never terminate during the lifetime of the application - they are written as infinite loops with blocking calls that wait for some sort of signaling from other threads or I/O operations.
2) Continual create/terminate/destroy of thread objects is expensive, difficult to control, awkward-to-debug, unreliable and generally causes pain.
3) If your multithread code contains any of the following:
Suspend()
Resume(), (except in some thread ctors)
Join()
Abort()
IsAlive()
You should probably think again :)
I know you're only learning, but sometimes it's better to patch up holes before they get any bigger :)

You are creating instance of Thread's in the Button Click events, so the if statement that checks threadX.IsAlive will throw error reporting null reference exception
So please create the instance of thread1 & 2 on load

Check for null also.
Use Abort() method instead of Suspend() as you are anyway creating a new thread each time.
private void button1_Click(object sender, EventArgs e)
{
if (thread2!=null && thread2.IsAlive)
{
thread2.Abort();
}
thread1 = new Thread(threadOne);
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
if (thread1!=null && thread1.IsAlive)
{
thread1.Abort();
}
thread2 = new Thread(threadTwo);
thread2.Start();
}

Related

Why is this simple code causing my app to freeze?

My app kept freezing with no reason so I simplified the code until I contained the problem.
Apparently having two synclock (one in a simple sub and another in a timer) caused it. This is the simplified code:
String var1 = "";
String var2 = "";
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(test_sub);
thread.Start();
}
private void test_sub()
{
lock (var1)
{
Thread.Sleep(1000000);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (var2){}
}
Timer 1 is enabled by default with 1s delay between ticks. As soon as button1 is press, the UI freezes. Can anyone please explain what's causing this weird behavior and what can be done about it? Thanks!
Your problem is not in the Thread, or in the lock per se.
The problem is in the objects used to lock: the two locks are locking on the empty string, which is optimized to use the String.Empty instance.
So your code reads:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(test_sub);
thread.Start();
}
private void test_sub()
{
lock (String.Empty)
{
Thread.Sleep(1000000);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (String.Empty){}
}
Which is going to lock the UI thread as soon as timer1_Tick is entered, because the timer (running on the UI thread) is going to lock the same object instance as the test_sub (running on a separate thread).
To ensure two locks are used, you should declare your lock objects like this:
private readonly object _lock1 = new object();
private readonly object _lock2 = new object();
This guarantees no external locking happens on the same objects, and that the two lock objects are distinct instances.

Moving pictureBox with thread programming

I want to move picturebox with thread programming. Also, I want to get Picturebox's count with a Textbox in my solution, but it's my first try so I have problems with it. Could you please help me?
Thread th;
public void F_Thread()
{
for (int i = 0; i < Convert.ToInt16(textBox1.Text); i++)
{
this.pictureBox1.Left = this.pictureBox1.Left - 10;
Thread.Sleep(100);
}
}
private void button1_Click_1(object sender, EventArgs e)
{
th = new Thread(F_Thread);
th.Start();
}
Here is a cheap, minimal example of using Invoke to change a property of a control from a different thread:
public void F_Thread()
{
for (int i = 0; i < Convert.ToInt16(textBox1.Text); i++)
{
if (pictureBox1.InvokeRequired )
this.Invoke(new UpdatePBInvoker(UpdatePB), -10);
Thread.Sleep(100);
}
}
delegate void UpdatePBInvoker(int moveX);
private void UpdatePB(int moveX)
{
pictureBox1.Left = pictureBox1.Left + moveX;
}
Feel free to add more parameters; just make sure to keep the signatures of the function and the delegate the same:
delegate void UpdatePBInvoker(Control ctl, int moveX);
private void UpdatePB(Control ctl, int moveX)
{
ctl.Left = ctl.Left + moveX;
}
Call the 2nd version like this:
.. this.Invoke(new UpdatePBInvoker(UpdatePB), pictureBox1, -10);
Note the the check if ( someControl.InvokeRequired ) is optional and often added to allow for the option of not calling the function from a different thread; for theses cases one usually adds an else branch with the direct call: UpdatePB(...)
Also note that the thread may still run when you close the Form. To prevent errors make sure to abort it, maybe like this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if ((th!= null && th.IsAlive) th.Abort();
}
If your thread would do more complicated things, especially aquiring locks, it should not be aborted but given a chance to finish and close itself, usually by setting a global flag. But in this case it should work ok. Also see MSDN on this topic..

How do I make a repeating button with a thread in c#?

I've looked at some guides and none of them have gotten me all the way there. I've never made a thread, discussed a thread, or seen a thread at the grocery store, so this may be a problem. Currently. I'm trying:
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
{
ThreadStart HUp = new ThreadStart(dothis);
t = new Thread(HUp);
t.Start();
}
}
public void dothis()
{
if (intHour < 23)
intHour = intHour += intStep;
lblTimerHour.Text = intHour.ToString("00");
}
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
t.Abort();
}
}
That gets me InvalidOperationException was unhandled on the
lblTimerHour.Text = intHour.ToString("00");
line. I read what that means and... it might as well be in Mandarin, I kind of get the general concept-ish of what's going wrong, but it's painfully fuzzy. If you asked me the first step in fixing it I'd look at you like a deer in the headlights. We just haven't gotten that far in my class yet.
The problem here is that the label you are trying to update is owned by the main thread (i.e. what the UI runs on), and that means that only that thread can access/update it. So, since you are in a different thread, you need to tell the UI thread to update the label for you.
Something like this would work:
Action updateLabel = () => lblTimerHour.Text = intHour.ToString("00");
lblTimerHour.BeginInvoke(updateLabel);
What this does is tell the lblTimerHour to invoke the action you define above (updateLabel).
See this post: How to update the GUI from another thread in C#?
lblTimerHour.Invoke((MethodInvoker)delegate {
//Do what you need to do with the label
lblTimerHour.Text = intHour.ToString("00");
});
Edit
This should do the trick:
public void dothis()
{
do
{
if (intHour < 23)
intHour = intHour += intStep;
lblTimerHour.Invoke((MethodInvoker)delegate {
//Update the label from the GUI thread
lblTimerHour.Text = intHour.ToString("00");
});
//Pause 1 sec. Won't freeze the gui since it's in another thread
System.Thread.Sleep(1000);
}while(true); //Thread is killed on mouse up
}
Well, let's take a look and see what you already have.
First, I see you did this.
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
ThreadStart HUp = new ThreadStart(dothis);
t = new Thread(HUp);
t.Start();
}
While this certainly is not the freshest stuff around it will still work. If you wanted some fresher ingredients then you might go with this instead.
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
Task.Factory.StartNew(dothis);
}
Second, I see this.
public void dothis()
{
if (intHour < 23) intHour = intHour += intStep;
lblTimerHour.Text = intHour.ToString("00");
}
The problem here is that you are attempting to update a UI control from a thread other than the main UI thread. You see UI controls have what is called thread affinity. They can only ever be accessed from the thread that created them. What you have will lead to all kinds of unpredictable problems up to and including tearing a whole in spacetime.
A better option would be to do this.
public void dothis()
{
while (intHour < 23)
{
intHour = intHour += intStep;
lblTimerHour.Invoke((Action)(
() =>
{
lblTimerHour.Text = intHour.ToString("00");
}));
}
}
I assumed that you were missing the loop so I added it. While I cannot say that I personally have a taste for this kind of thing it is much easier to swallow. The real problem here is that the worker thread really does not do a whole lot of useful work. And then to top it off we have to use an awkward marshaling operation to transfer the result back to the UI thread. It is not pretty, but it will work.
And finally that brings me to this.
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
t.Abort();
}
You are attempting to abort a thread which is highly inadvisable. The problem is that it yanks control from the thread at unpredictable times. That thread might be in the middle of a write to data structure which would corrupt it. This is actually a pretty bad problem because any data structure in the process of being manipulated from any one of the frames on the call stack could be in an inconsistent state. This includes code you did not write. That is why it is hard to say what you may or may not be corrupting by doing this.
What you need to consider instead is using the cooperative cancellation mechanisms. This includes the use of CancellationTokenSource and CancellationToken. Here is how it might look once we put everything together.
private CancellationTokenSource cts = null;
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
cts = new CancellationTokenSource();
Task.Factory.StartNew(() => dothis(cts.Token));
}
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
cts.Cancel();
}
public void dothis(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
intHour += intStep;
lblTimerHour.Invoke((Action)(
() =>
{
lblTimerHour.Text = intHour.ToString("00");
}));
Thread.Sleep(1000);
}
}
What this does is signal that the worker thread should gracefully shutdown on its own. This gives the worker thread a chance to tidy things up before eventually terminating itself.
If you want to update the UI every X period of time then there are already existing tools for this; a Timer will do exactly what you want, and it will be much more efficient and easier to code than creating a new thread that just spends most of its time napping. Additionally, aborting threads is a very bad sign to see. Avoid it at all costs.
First create the timer and configure it in the constructor:
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
private int hour = 0;
private int step = 0;
public Form1()
{
InitializeComponent();
timer.Tick += timer_Tick;
timer.Interval = 1000;
}
Have the Tick event do whatever should be done whenever it ticks.
private void timer_Tick(object sender, EventArgs e)
{
if (hour < 23)
{
hour += step;
lblTimerHour.Text = hour.ToString("00");
}
}
Then just start the timer when you want it to start ticking and stop the timer when you want it to stop:
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
timer.Start();
}
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
timer.Stop();
}
The timer will automatically ensure that the Tick event handler runs in the UI thread, and it won't block the UI thread (or any other thread) when its waiting for the next event to happen, it will just do nothing.

While sequence inside a timer tick in C#

I have a timer of 1 second in C#, with a while sequence in it. My question is if the while sequence is not finished before 1 second, will the timer tick, and restart the while from the beginning?
The part of the code is below, and what it does is that it cycles through the selected objects and changes something. So, if there are a lot of objects selected and I need more than 1 second to change them, will they all be changed?
P.S. I actually want the loop to be broken; a large number of objects will be selected only by mistake, but I just want to be sure that I avoid this possibility. :)
private void timer1_Tick(object sender, EventArgs e)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
}
Yes, timer ticks can happen concurrently. This means that your timer must be thread-safe.
Except for the UI timer classes (WinForms/WPF). Their tick functions run on the UI thread. With DoEvents you can cause reentrancy even there which is another reason to avoid DoEvents.
From the name of the handler I assume you are using System.Windows.Forms.Timer which is single-threaded. That means the Tick event will fire after the previous one has ended. To break the loop, you will have to execute the code in another thread an use an exit condition.
This is how I usually do it:
private bool running;
private bool restart;
private void DoWork(object item)
{
running = true;
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext() && !restart)
{
//do your stuff
if (myEnum.Current != null) {....}
}
if(restart)
{
restart = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (running)
restart = true;
else
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
A workaround would be to disable the timer at the top of the while event, and re-enable it as you exit the while event.
The while loop will not be broken because the timer has ticked again. But in any case, your best bet would be to disable the timer at the beginning of the event handler, and re-enable it again at the end.
You could always try something similar to this instead, that way you void having multiple timers tick over and kick off processes. Written in Notepad so please excuse any massive spelling mistakes
private Timer _systemTimer = null;
public MyApp()
{
_systemTimer = new Timer("how ever you set your 1 second);
// Create your event handler for when it ticks over
_systemTimer.Elapsed += new ElapsedEventHandler(systemTimerElapsed);
}
protected void systemTimerElapsed(object sender, ElapsedEventArgs e)
{
_systemTimer.Stop();
//Do what you need to do
_systemTimer.Start();
//This way if it takes longer than a second it won't matter, another time won't kick off until the previous job is done
}
I will make it very easy for you;use Thread.Sleep() in another background thread and it is done!
If you know when are you finish than just use AutoResetEvent to keep threads in sync.
If you do not have any control on the update no callback , time is unknown I suggest to increase your timer interval!
var thread = new Thread((ThreadStart)delegate
{
While(true)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
Thread.Sleep(1000);
}
}
thread.Start();
Get each char from string from txtString and write on label one by one char with timerControl
int g = 0;
private void timerString_Tick(object sender, EventArgs e)
{
string a = txtString.Text;
int em = txtString.TextLength;
if (g < em)
{
lblString.Text = lblString.Text + a[g];
g++;
}
else timerString.Stop();
}
Call from
private void btnStringStart_Click(object sender, EventArgs e)
{
timerString.Start();
lblString.Text = "";
}

Using Console.WriteLine in a BackgroundWorker doWork event

I have a console application that utilizes the BackgroundWorker object and wanted to test my output with a Console.WriteLine(fooBar). However, that application exits as the application executes the Console.WriteLine command.
Here's a watered down version that illustrates what I wanted to do:
protected static void bWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = startId; i <= endId; i++)
{
Console.WriteLine(i.ToString());
Thread.Sleep(1000);
}
}
Any ideas why the application would appear to exit like that?
The application exits because it in fact completes execution and has no more work to do ;-) Once you schedule the background worker and kick off the thread to do it's thing, you have to tell the main thread to stop and wait for one thing or another. A very common way of doing this (Generally used in test/sample code) is to simply issue a Console.ReadKey(); as the very last line of code in your main method. This will cause your application to wait until you press a key before exiting the process.
For your backgroundworker set WorkerReportsProgress to true. Subscribe to ProgressChanged event like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (var i = 0; i < 1000; i++)
{
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage);
}
If you need to transfer more than just int from your background thread to UI thread, then you could do something like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (var i = 0; i < 1000; i++)
{
var myObjectInstance = new MyObject{ ...};
backgroundWorker1.ReportProgress(null, myObjectInstance);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var myObjectInstance = (MyObject)e.UserState;
Console.WriteLine(myObjectInstance);
}
I might not be understanding your setup correctly. I'm guessing that you're running the background thread, but the main process is exiting which causes the thread to be stopped before it gets to do anything. Maybe try putting something in your main process that prevents the main thread from exiting like Console.ReadKey();

Categories