I want to show an example application of semaphores for a specific problem for my homework.
I added 3 buttons to my C# form and I want to show that only one button at a specific time executes the bank account function in my code. When I click the three buttons in two seconds, the bank account function must run only one time. Because I have a Thread.Sleep(6000) for 6 seconds wait in bank account function. But three of my click runs by 6 second intervals consecutively. How can I change my code to run only one time when I press three buttons consecutively.
The Code is:
namespace semafor_form
{
public partial class Form1 : Form
{
Semaphore semafor=new Semaphore(1,1);
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.textBox2.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox2.Text = text;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void BankAccount()
{
semafor.WaitOne();
double a = Convert.ToDouble (textBox1.Text) + Convert.ToDouble (textBox2.Text);
Thread.Sleep(6000);
semafor.Release();
SetText(a.ToString());
}
private void btnATM_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(BankAccount));
t.Start();
}
private void btnCOUNTER_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(BankAccount));
t.Start();
}
private void btnINT_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(BankAccount));
t.Start();
}
}
}
I may have misread your question. You don't want the buttons to do anything when the thread is being used? (so you'll miss transactions?)
Try this:
private void BankAccount()
{
if (semafor.WaitOne(0))
{
double a = Convert.ToDouble (textBox1.Text) + Convert.ToDouble (textBox2.Text);
Thread.Sleep(6000);
semafor.Release();
SetText(a.ToString());
}
}
Try changing Semaphore semafor=new Semaphore(1,1); to Semaphore semafor=new Semaphore(0,1);
You are initializing a new semaphore without ever releasing it.
This really doesn't sound like an appropriate use of a semaphore. Your problem definition, if I'm reading it correctly, says that the three buttons are mutually exclusive: that pressing any one of them will render all of the buttons inactive for six seconds. You can use a semaphore for this, but a mutex would be more appropriate.
In any event, the problem you're experiencing is that you're waiting on the semaphore, so when the first transaction is done one of the other threads will acquire the semaphore and process. What you want to do is to try to acquire the semaphore. Here's an example.
An example of the latter:
private void BankAccount()
{
if (semafor.WaitOne(0)) // tries to acquire the semaphore
{
double a = Convert.ToDouble (textBox1.Text) + Convert.ToDouble (textBox2.Text);
Thread.Sleep(6000);
semafor.Release();
SetText(a.ToString());
}
}
The WaitOne(0) says, "Try to acquire the semaphore. If it's not immediately available, then return false. If it is available, acquire it and return true."
You could also do this in the button handler. That is, have the button handler acquire the semaphore (using WaitOne(0)), and have it exit without starting the thread if it can't acquire the semaphore. If it does acquire the semaphore, start the thread and have the thread proc release the semaphore when done.
Related
Is it possible to stop an ongoing process with a button click in Windows form application?
For example, let's say there are 2 buttons, "START" and "STOP"
When you press "START", it will start an infinite loop, printing numbers from 1 to infinity.
When I press "STOP", the process should stop at that moment.
But the problem is, I cannot press the "STOP" button as it does not allow me, since there's an ongoing process.
Is there a way to overcome this?
I know there's something called "MethodInvoker", but I have no idea how that works or whether it is relevant to this.
private bool keepRunning = true;
public Form1()
{
InitializeComponent();
}
private void StartBtn_Click(object sender, EventArgs e)
{
var number = 1;
while (keepRunning)
{
Thread.Sleep(1000);
MesgeLabel.Text = "" + number++;
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
//Cannot even click this button
keepRunning = false;
//or
Application.Exit();
}
EDIT 1:
If you need to interact with UI controls, doing it from a background task would throw invalid operation -> illegal cross thread exception. To overcome this,
check Control.InvokeRequired
if(myLabel.InvokeRequired)
myLabel.Invoke(new Action(() => myLabel.Text = newText));
else
myLabel.Text = newText;
You can start a Task by providing a CancellationToken and cancel the operation when the stop button is clicked.
The task will execute the infinite loop on another thread and your main thread (the UI thread) should not be affected and should be accessible.
Try this:
/*
Please add these on top of your form class
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
*/
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cancellationTokenSource;
CancellationToken cancellationToken;
private void CountToInfinity()
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
Debug.WriteLine(new Random().Next());
}
}
private async void button1_Click(object sender, EventArgs e)
{
if (cancellationTokenSource == null)
{
cancellationTokenSource = new CancellationTokenSource();
cancellationToken = cancellationTokenSource.Token;
Task.Run((Action)CountToInfinity, cancellationToken);
}
}
private void button2_Click(object sender, EventArgs e)
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
}
If you have spawned a new process then you can call kill method.
Process myProcess = Process.Start("Notepad.exe")//starts new process
myProcess.Kill();// kills the process. save reference to myProcess and call kill on STOP button click
If you have started new thread then call abort method to stop the thread.
Thread thread = new Thread(new ThreadStart(method));
thread.Start();
thread.Abort(); // terminates the thread. call abort on STOP button click
When you press the "start" button, the code that runs and prints the numbers will run on the ui thread. (from your explanation, i assume that all you have is the message handler for the button press event and nothing else. e.g.: Not setting up a seperate thread.).
Running an infinite loop on the ui thread means, that you do not get any more time for processing other messages. (the thread that is responsible for processing the ui messages is stuck in your infinite loop.)
So, in order to be able to press the "stop" button, you need to run the code with the infinite loop in a different thread or in a different process altogether. This is what Arjun is trying to tell you. (if you want the code in the infinite loop to access resources from your form app, you need a thread. [the thread is inside the forms app process.])
please note: if you create a thread and run your number printing code inside that thread, this will not be the ui thread. Thus, you will not be able to interact with the forms controls as if you'd be on the ui thread. (i.e.: trying to set the windows.text in order to display your numbers will most likely throw an exception.)
I have trouble making the main thread of my program in my windows form work properly, as it freezes and does not paint my objects for a while. I will explain it with a dummy example.
Let's say we have :
a train thread running around a track,
a wagon thread waiting in a place on the same track,
and a main thread painting the objects in the windows form.
the train and wagon threads start as follow :
public PanelThread train, wagon;
private Thread thread1, thread2;
train = new PanelThread(new Point(10, 10),
150, Direction.West, Track.track1, pnl1, typetrain.loco,
Color.Blue,
semaphore
);
wagon = new PanelThread(new Point(390, 390),
150, Direction.West, Track.track1, pnl1, typetrain.loco,
Color.Blue,
semaphore
);
thread1 = new Thread(new ThreadStart(train.Start));
thread2 = new Thread(new ThreadStart(wagon.Start));
thread1.Start();
thread2.Start();
And in the PanelThread class : (the code is specific and only added as asked in comments)
public void Start()
{
Color signal = Color.Red;
Thread.Sleep(delay);
if (this.locwag == typetrain.loco)
{
work();
}
else
{
for (;;)
{
if (greenclicked == true)
{
workwagon();
break;
}
}
}
}
Now, when we click on a button, we launch a function like as follow :
private void button7_Click(object sender, EventArgs e)
{
for(;;)
{
if(train.variable1 == true)
{
break;
}
}
wagon.variable2 = true;
}
the variable1 is always false except when the train is on the same place as the wagon (done by checking if the train is at a certain point in a for loop, like at the end of the second passage i.e counter_variable = 2).
Now, the thing is that the for loop is taking all the place in the ain thread and not letting it paint the objects, even though the other thread still work, and the painting resumes after the function is finished.
I tried putting this loop in a function in the train thread launched by the button7_clicked function like this :
private void button7_Click(object sender, EventArgs e)
{
train.waitingfunction();
wagon.variable2 = true;
}
But the result is the same as the function waits for the waitingfunction() to be done.
I then thought I would need to completely delegate the work on another thread, using invoke, but I admit I do not understand yet how it exactly works. so I wrote it like this, using invoke on the panel.
private void button7_Click(object sender, EventArgs e)
{
if (panel.InvokeRequired)
{
panel.Invoke(new MethodInvoker(delegate{train.waitingfunction();}));
}
wagon.variable2 = true;
}
As of now there is no freeze anymore but the wagon automatically starts, I am guessing the function never goes in the if statement and I am now completely lost. Any idea on how to work around the problem ?
UPDATE : here is the answer, in the Waitingfunction called waitingwagon in my program, I used AutoResetEvent like this :
public void waitingwagon()
{
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
while (!autoResetEvent.WaitOne(TimeSpan.FromSeconds(0.1)))
{
if (waitinggreen == true)
{
break;
}
}
}
what you want to avoid is for(;;) in your main thread, because that blocks your thread ...
your 2nd thread (wagon) basically has to do nothing, until that status changes, so you could use a event wait handle (e.g. manual/auto reset event) and block your wagon thread with that until that event fires ...
but of course if you have side constraints like "a button has to be clicked" etc you will have to add additional logic to handle that... it's not really possible to provide a working example for your specific problem, since you did not provide a compilable sample, but if you google event wait handles and look for examples on manualresetevent or autoresetevent, you should find something you can adapt
I have some controls on the form of the Windows Forms application and I need to update its' texts at run-time from several threads.
Is it safe to just call BeginInvoke method like this:
BeginInvoke((MethodInvoker)delegate()
{
this.label.Text = "Some text";
});
from several threads at the same time? Should I do any additional synchronization in this case? Will it be processed by the same thread one by one and is this order guaranteed?
Thanks in advance.
Calling BeginInvoke puts the delegate on to the message queue to be processed by the UI thread, it will process the queue handling the messages one by one. So no, you do not need to do any additional synchronization (as long as the delegate is not accessing any resources that can't be accessed from the UI thread).
As for order, it is not guaranteed they will be processed in order but in practice most of the time the delegates will be processed in the order they where put in to the queue.
To address the question in the comments, instead of using multiple BeginInvoke calls you should be able to get away with just one.
You never really explained what your animation was so I am going to assume it is going to be that this.label will swap between ., .. and ... then you store the result text in this.label when you are done.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
animationTimer = new System.Windows.Forms.Timer();
animationTimer.Interval = 500;
animationTimer.Tick += animationTimer_Tick;
}
private System.Windows.Forms.Timer animationTimer;
private int dots = 0;
void animationTimer_Tick(object sender, EventArgs e)
{
//Make 1, 2, or 3 dots show up. This runs on the UI thread so we don't need to invoke.
this.label.Text = new String('.', dots + 1);
//Add one then reset to 0 if we reach 3.
dots += 1;
dots = dots % 3;
}
private void button1_Click(object sender, EventArgs e)
{
animationTimer.Start();
Task.Run(() => DoSomeSlowCalcuation());
}
private void DoSomeSlowCalcuation()
{
Thread.Sleep(5000);
this.BeginInvoke((MethodInvoker)delegate()
{
//We stop the timer before we set the text so the timer will not overwrite it.
animationTimer.Stop();
this.label.Text = "Some text";
});
}
}
This code is just a example to get my point across, if I where doing this I would use async/await for the button click and not use BeginInvoke at all.
private async void button1_Click(object sender, EventArgs e)
{
animationTimer.Start();
var result = await Task.Run(() => DoSomeSlowCalcuation());
animationTimer.Stop();
this.label.Text = result;
}
private string DoSomeSlowCalcuation()
{
Thread.Sleep(5000);
return "Some text";
}
In this code, when button1 is clicked twice, it creates 2 separate threads. On one click, it creates a new thread on the heap and field t1 points to the new thread on the heap. When I click button2, it aborts the last thread (which t1 refers to).
How do I abort the other thread?
Thread t1;
ThreadStart ts1;
private void button1_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(myfunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
t1.Abort();
}
Well, the OO answer would be to hold a list of threads as a field.
private readonly List<Thread> threads = new List<Thread>();
And to then add the newly constructed thread to the list in the first handler.
var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);
Then you could iterate through each thread in the second handler, aborting each of them in turn.
foreach(var thread in threads)
thread.Abort();
But I think the most important point here is that there is almost never a good reason to call Thread.Abort.
From the MSDN page:
When a thread calls Abort on itself,
the effect is similar to throwing an
exception; the ThreadAbortException
happens immediately, and the result is
predictable. However, if one thread
calls Abort on another thread, the
abort interrupts whatever code is
running. There is also a chance that a
static constructor could be aborted.
In rare cases, this might prevent
instances of that class from being
created in that application domain. In
the .NET Framework versions 1.0 and
1.1, there is a chance the thread could abort while a finally block is
running, in which case the finally
block is aborted.
The thread that calls Abort might
block if the thread that is being
aborted is in a protected region of
code, such as a catch block, finally
block, or constrained execution
region. If the thread that calls Abort
holds a lock that the aborted thread
requires, a deadlock can occur.
You would be much better off using some form of signalling, such as setting a ManualResetEvent that each thread will poll at perioidic intervals. Alternatively, you could use the BackgroundWorker class that has some support for task-cancellation (call CancelAsync on it, and get the worker threads to test CancellationPending periodically). If you are on .NET 4.0, you can also use the TPL.
I would recommend you to take a look at the built in synchronization primitives such as ManualResetEvent and WaitHandle. You can ask a thread if it's running or not by trying to join the thread with Thread.Join. Aborting a thread should only be done as a last resort if the thread is unresponsive.
Here is an modified example of your code that shows how you can prevent the thread from be restarted before it's been stopped properly.
public partial class MainForm : Form
{
private Thread t1;
private ThreadStart ts1;
private ManualResetEvent t1resetEvent;
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null) {
if (!t1.Join(0)) {
// The thread seems to be running.
// You have to stop the thread first.
return;
}
}
t1resetEvent = new ManualResetEvent(false);
ts1 = new ThreadStart(MyFunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null)
{
// Set the reset event so the thread
// knows it's time to stop.
t1resetEvent.Set();
// Give the thread four seconds to stop.
if (!t1.Join(4000)) {
// It did not stop, so abort it.
t1.Abort();
}
}
}
private void MyFunc()
{
// Long running operation...
while (true)
{
// Do someone want us to exit?
if (t1resetEvent.WaitOne(0)) {
return;
}
}
}
}
The others have given the long versions of the answer, however the obvious simple solution is to simply skip recreating the thread object:
public partial class Form1 : Form
{
Thread thread1;
ThreadStart threadStart1;
public Form1()
{
InitializeComponent();
threadStart1 = new ThreadStart(threadTarget);
thread1 = new Thread(threadStart1);
thread1.Name = "Button1 thread";
}
private void button1_Click(object sender, EventArgs e)
{
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread1.Abort();
}
private void threadTarget()
{
Console.WriteLine(Thread.CurrentThread.Name);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
}
}
However, I would consider reading up on Threading in .NET using one these guides (I'd recommend Joseph Albahari's guide on aborting - the author of C# in a nutshell) rather than use this method, particularly if you're performing IO or database operations which can leave the objects in unexpected states.
Also, have in mind that calling Abort on a Thread is evil. You should stop the thread with a boolean condition or something like that.
Check this:
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
I have some unsolved issue with threads. It's my first time doing it. I know how to use one thread to write in a textBox, but I have no idea how to use two of them to do the job. Anyone have a clue what do I have to do to be able to use two threads to write to the same textBox, but not in the same time. Thank you.
Here's an example that uses two threads to write random numbers to a multi-line text box. As Brandon and Jon B noted, you need to use Invoke() to serialize the calls to the GUI thread.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Random m_random = new Random((int)DateTime.Now.Ticks);
ManualResetEvent m_stopThreadsEvent = new ManualResetEvent(false);
private void buttonStart_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(new ThreadStart(ThreadOne));
Thread t2 = new Thread(new ThreadStart(ThreadTwo));
t1.Start();
t2.Start();
}
private void ThreadOne()
{
for(;;)
{
int n = m_random.Next(1000);
AppendText(String.Format("One: {0}\r\n", n));
if(m_stopThreadsEvent.WaitOne(n))
{
break;
}
}
}
private void ThreadTwo()
{
for(;;)
{
int n = m_random.Next(1000);
AppendText(String.Format("Two: {0}\r\n", n));
if(m_stopThreadsEvent.WaitOne(n))
{
break;
}
}
}
delegate void AppendTextDelegate(string text);
private void AppendText(string text)
{
if(textBoxLog.InvokeRequired)
{
textBoxLog.Invoke(new AppendTextDelegate(this.AppendText), new object[] { text });
}
else
{
textBoxLog.Text = textBoxLog.Text += text;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
m_stopThreadsEvent.Set();
}
}
Another option is to use a Thread Callback method. This is a method that exists on the main thread, but when creating a new thread you pass a handle/reference to this method. This allows the second thread to call the method on the main thread and the functionality to update/check the textbox would sit there.
Look into passing delegates between threads.
One option you could do, is push messages onto a Queue object and use a timer on the windows form to read messages from this queue and write to the textbox.
In order to make everything nice and threadsage you could lock the Queue object when reading and writing to it.
For example:
private Queue<string> messages = new Queue<string>();
/// <summary>
/// Add Message To The Queue
/// </summary>
/// <param name="text"></param>
public void NewMessage(string text)
{
lock (messages)
{
messages.Enqueue(text);
}
}
private void tmr_Tick(object sender, EventArgs e)
{
if (messages.Count == 0) return;
lock (messages)
{
this.textBox.Text += Environment.NewLine + messages;
}
}
safest approach is to only have 1 thread be able to work on the text box (or any gui object), have any other threads that need to perform an action on the text box communicate their needs to the thread that controls the text box.
so your question becomes how to communicate between threads, this is going to be language/OS specific so you need to provide more information.
This MSDN Article explains how to make thread safe calls to windows form controls.
You can only access GUI components from the main thread. To write to a textbox from another thread, you need to use BeginInvoke().