I'm trying to run an ATM Simulation in C# with Windows Forms that can have more than one instance of an ATM machine transacting with a bank account simultaneously.
The idea is to use semaphores/locking to block critical code that may lead to race conditions.
My question is this:
How can I run two Forms simultaneously on separate threads? In particular, how does all of this fit in with the Application.Run() that's already there?
Here's my main class:
public class Bank
{
private Account[] ac = new Account[3];
private ATM atm;
public Bank()
{
ac[0] = new Account(300, 1111, 111111);
ac[1] = new Account(750, 2222, 222222);
ac[2] = new Account(3000, 3333, 333333);
Application.Run(new ATM(ac));
}
static void Main(string[] args)
{
new Bank();
}
}
...that I want to run two of these forms on separate threads...
public partial class ATM : Form
{
//local reference to the array of accounts
private Account[] ac;
//this is a reference to the account that is being used
private Account activeAccount = null;
private static int stepCount = 0;
private string buffer = "";
// the ATM constructor takes an array of account objects as a reference
public ATM(Account[] ac)
{
InitializeComponent(); //Sets up Form ATM GUI in ATM.Designer.cs
this.ac = ac;
}
...
I've tried using
Thread ATM2 = new Thread(new ThreadStart(/*What goes in here?*/));
But what method do I put in the ThreadStart constructor, since the ATM form is event-driven and there's no one method controlling it?
EDIT:
I've tried replacing Application.Run(new ATM(ac)); with
ATM atm1 = new ATM(ac);
ATM atm2 = new ATM(ac);
Thread ATM2_T = new Thread(new ThreadStart(atm1.Show));
Thread ATM1_T = new Thread(new ThreadStart(atm2.Show));
ATM1_T.Start();
ATM2_T.Start();
in the Bank constructor. Nothing is displayed and the program drops-off the end of the Main() function.
Here's what I think you need to do:
Thread ATM2 = new Thread(new ThreadStart(ThreadProc));
ATM2.Start();
It calls this method:
private void ThreadProc()
{
var frm = new ATM();
frm.ShowDialog();
}
The above is unsafe code
Please find the threadsafe code:
Thread ATM2 = new Thread(new ThreadStart(ThreadProc));
ATM2.Start();
It calls this method:
private void ThreadProc()
{
if(InvokeRequired)
{
this.Invoke(new Action(() => CreateAndShowForm()));
return;
}
CreateAndShowForm();
}
private void CreateAndShowForm()
{
var frm = new ATM();
frm.ShowDialog();
}
In Bank.Main(), try relpacing Application.Run(new ATM(acc)) with new ATM(acc).Show(). You can use the Form.Show() method as many times as you want. If I recall correctly, the application will close when all forms are closed (although I could be mistaken--try this with the VS debugger)
Related
I have a c# program.
the form1 of the program makes new instances of form3 on different thread from time to time.
so each of the form3 instances contains these methods.
I suspect that the problem occours when two threads calls the same method at the same time or while another thread is allready using one of them. especially because they have the same webbrowser name
private void vent()
{
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
}
public bool containss(string SearchText)
{
string page = wb.Document.Body.InnerText;
if (page.ToLower().Contains(SearchText.ToLower()))
return true;
else return false;
}
The Problem with this containss() method is that it works with
string page = wb.Document.Body.InnerHtml;
and not
string page = wb.Document.Body.InnerText;
I get: Object reference not set to an instance of an object.
on this line:
if (page.ToLower().Contains(SearchText.ToLower()))
I make the threads like this:
private void ThreadProc()
{
Form frm = new Form3(currentAB);
frm.ShowDialog();
}
Thread ab1 = new Thread(new ThreadStart(ThreadProc));
ab1.SetApartmentState(ApartmentState.STA);
ab1.Start();
Currently, I am using a thread to autofill a zedgraph chart. The problem is that it is very slow and that is not good for the production.
Knowing that:
1. There is a Thread running background to get fresh data from remote server and store them in a local text file.
2. There is another Thread accesses and reads data from the local file and refresh the zedgraph chart.
Personnaly I think this makes the application running very slowly.
Timer component may be better to handle this kind of stuff.
Does anyone has experience in ZedGraph Live Data?
Or any advice would be welcomed.
EDIT: UPDATE UI
Also I would like to know how to update the UI within a Thread so that the user does not have to close and open the form to view the chart.
Thanks
The way I would go about this is as follows:
You make a class that holds the data (this can also be the same class you already have) for the example I will call it InformationHolder.
class InformationHolder {
private static InformationHolder singleton = null;
public List<float> graphData; //Can be any kind of variable (List<GraphInfo>, GraphInfo[]), whatever you like best.
public static InformationHolder Instance() {
if (singleton == null) {
singleton = new InformationHolder();
}
return singleton;
}
}
Now you need a class that will get your information in the background, parses it and inserts it into the above class.
Example with Thread.Sleep():
class InformationGartherer {
private Thread garthererThread;
public InformationGartherer() {
garthererThread = new Thread(new ThreadStart(GartherData));
}
private void GartherData() {
while (true) {
List<float> gartheredInfo = new List<float>();
//Do your garthering and parsing here (and put it in the gartheredInfo variable)
InformationHolder.Instance().graphData = gartheredInfo;
graphForm.Invoke(new MethodInvoker( //you need to have a reference to the form
delegate {
graphForm.Invalidate(); //or another method that redraws the graph
}));
Thread.Sleep(100); //Time in ms
}
}
}
Example with Timer:
class InformationGartherer {
private Thread garthererThread;
private Timer gartherTimer;
public InformationGartherer() {
//calling the GartherData method manually to get the first info asap.
garthererThread = new Thread(new ThreadStart(GartherData));
gartherTimer = new Timer(100); // time in ms
gartherTimer.Elapsed += new ElapsedEventHandler(TimerCallback);
gartherTimer.Start();
}
private void TimerCallback(object source, ElapsedEventArgs e) {
gartherThread = new Thread(new ThreadStart(GartherData));
}
private void GartherData() {
List<float> gartheredInfo = new List<float>();
//Do your garthering and parsing here (and put it in the gartheredInfo variable)
InformationHolder.Instance().graphData = gartheredInfo;
graphForm.Invoke(new MethodInvoker( //you need to have a reference to the form
delegate {
graphForm.Invalidate(); //or another method that redraws the graph
}));
}
}
To get the reference to the form you could do the same trick as I used with the InformationHolder: using a singleton.
When you want to use the information just get it from the InformationHolder like so:
InformationHolder.Instance().graphData;
As I said this is how I personally would solve this. There might be a better solution I'm not aware of. If you have any questions you can post them below.
I'm writing a small app that will be the endpoint for NLog Network targets (Sending debug messages over TCP) The app uses Sockets to create a server and accept connections. This application is windowless and starts up in the System Tray using NotifyIcon and ApplicationContext. The application listens on a port, when it receives it's first message from a unique endpoint it will create a new window and display it (These windows will contain the actual debug messages) I've been able to get the window to display but it's displaying as if it's hung, I'm guessing it's because it is getting created from on of the invisible threads created by the Sockets.
How can I properly create a new Windows.Form from the test_ClientConnected event?
Here is the ApplicationContext Code
public NLApplicationContext()
{
NLServer test = new NLServer();
test.ClientConnected += test_ClientConnected;
test.Start();
}
void test_ClientConnected(object sender)
{
Form2 newForm = new Form2((NLClient)sender);
newForm.Invoke(new MethodInvoker(() => {newForm = new Form2((NLClient)sender);}));
newForm.Invoke(new MethodInvoker(() => { newForm.Show(); }));
Console.WriteLine("Connected");
/*if (((NLClient)sender).testy.InvokeRequired)
{
((NLClient)sender).testy.BeginInvoke(new MethodInvoker(((NLClient)sender).testy.Show()));
return;
}*/
}
Here is the programs entry point
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new NLApplicationContext());
}
}
You can delegate the UI work to a separate thread like this :
void test_ClientConnected(object sender)
{
Thread displayFormThread = new Thread(ParameterizedThreadStart(DisplayForm));
displayFormThread.Start(sender);
}
private void DisplayForm(object sender)
{
Form2 newForm = new Form2((NLClient)sender);
newForm.Show();
}
You had the right idea, instead of creating the form in the socket thread, move the code to create the form and show it into a method, then Dispatcher.Invoke the method to execute it on the UI thread.
Finally figured out a different way that allowed me to create the form in the main UI thread.
NLApplicationContext
class NLApplicationContext : ApplicationContext
{
List<Form2> _connections; // Temp storage for now
SynchronizationContext testS;
public NLApplicationContext()
{
testS = SynchronizationContext.Current;
_connections = new List<Form2>();
NLServer test = new NLServer();
test.ClientConnected += test_ClientConnected;
test.Start();
}
void test_ClientConnected(object sender)
{
testS.Post(DisplayForm, sender);
}
private void DisplayForm(object sender)
{
Form2 newForm = new Form2((NLClient)sender);
newForm.Show();
_connections.Add(newForm); //Find better storage/sorting
}
}
Using a SynchronizationContext allows me to post back to the thread that it was created on.
I finished my little project that does some heavy lifting. i realized in this short calculation time, my GUI freezes. So I did some research and I found this => http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUI
I started to implement this is my project, but i realized that this particular implementation does not work in my project.
In my project i have many classes and one " manager " that controls all other classes. If i initilize this Manager class , it already does the heavy lifting in the constructor.
To my Question :
How do i start a new thread with a contructor ?
private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
if (System.IO.File.Exists(e.FullPath) == true)
{
Manager mgr = new Manager(e, handreader); // here starts the heavy lifting
Thread mgrThread = new Thread(new ThreadStart(mgr)); // what to do ?
sl.Text = mgr.test();
txtLog.Text = mgr.output();
}
}
EDIT :
okay i decided to recode my program. now the heavy lifting is in one function but i think i made a mistake.
the whole program looks like this :
private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
if (System.IO.File.Exists(e.FullPath) == true)
{
Manager mgr = new Manager(e, handreader, txtLog, sl);
//sl.Invoke(new MethodInvoker(mgr.test));
sl.Invoke(new MethodInvoker(mgr.test)); // first try
Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try
}
}
the sl.Invoke(new MethodInvoker(mgr.test)); // first try works but it still freezes my GUI.
Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try
and this line does nothing.
my test function :
public void test()
{
StringBuilder builder = new StringBuilder();
foreach (PlayerController pc in fm.lPc)
{
Range range = new Range(handReader.hand, handReader.handversus, pc);
builder.Append(pc.getHeroCardsSimple()+" vs 100% range = "+range.vsRange()+"\r\n");
}
sl.Text = builder.ToString();
}
You should use a different approach for this. Your constructor is still being invoked on the GUI thread.
Func<Manager> asyncConstructor;
private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
{
asyncConstructor = new Func<Manager>(() => new Manager());
asyncConstructor.BeginInvoke(ManagerConstructed, null);
}
private void ManagerConstructed(IAsyncResult result)
{
Manager mgr = asyncConstructor.EndInvoke(result);
//we can only access form controls from the GUI thread,
//if we are not on the gui thread then
//do the changes on the gui thread.
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
sl.Text = mgr.test();
txtLog.Text = mgr.output();
}));
}
}
Move the "heavy lifting" out of the constructor to some kind of "worker" and run that method in the thread.
Change the Manager from:
public Manager(/*params*/)
{
//params
//heavy lifting
}
to
public Manager(/*params*/)
{
//params
}
public void DoWork()
{
//heavy lifting
}
and the calling to
Manager mgr = new Manager(e, handreader);
Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork));
mgrThread.Start();
ATTENTION: If you access/change UI elements in the thread, don't forget to Invoke that calls!
Well, you could use:
Thread mgrThread = new Thread(() => new Manager(e, handreader));
... but then you won't have a reference to the manager for the rest of your code.
To be honest, doing the heavy lifting in the constructor is generally a bad idea anyway, for various reasons. It would be better to move that work somewhere else:
// Constructor just sets things up
Manager mgr = new Manager(e, handreader);
// DoWork method does the real work
Thread mgrThread = new Thread(mgr.DoWork);
I have an UI, a custom class, and a thread. I want to run the custom class completely in a separate thread. Is there a clean way of doing this?
For example. On the MainForm below, when UI calls _threadOneClass.Sleep, I need the UI to go to the spawned ThreadOne and invoke the Sleep method in ThreadOne, not in the main thread.
Basically, all method calls in MyClass need to be executed in ThreadOne, not in main thread. It is like, the MyClass runs on its own "process", while still visible to be called from MainForm.
The MainForm has 3 buttons, and 1 textbox for logging.
I was thinking of deriving the Thread class, but it is sealed. So deriving is definitely a wrong way per Microsoft.
Help dear experts?
Here is the output (MainThread ID=10, ThreadOne ID=11)
MyClass instantiated
Starting ThreadOne
11-Run.start
Sleeping ThreadOne
10-Run.sleep for 3000 'Need this to run on ThreadID 11
10-Run.woke up 'Need this to run on ThreadID 11
Stopping ThreadOne
11-Run.done
Here is how the code look like.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Thread _threadOneThread;
private MyClass _threadOneClass;
private void btnThreadOneCreate_Click(object sender, EventArgs e)
{
_threadOneClass = new MyClass(this);
_threadOneThread = new Thread(new ThreadStart(_threadOneClass.Run));
_threadOneThread.Start();
}
private void btnThreadOneStop_Click(object sender, EventArgs e)
{
_threadOneClass.IsRunning = false;
}
private void btnThreadOneSleep_Click(object sender, EventArgs e)
{
_threadOneClass.Sleep(3000);
}
public void Log(string txt)
{
MainForm.SetText(txtLog, txt);
}
internal static void SetText(Control ctl, string val)
{
if (ctl.InvokeRequired)
ctl.Invoke((MethodInvoker)delegate() { ctl.Text += Environment.NewLine + val; });
else
ctl.Text += Environment.NewLine + val;
}
}
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning) { }
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
public void Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
Threads allow you to run heavy operations while you continue doing other things. In the case of user interfaces (your scenario), asynchronous behavior is almost always necessary as blocking the UI thread will cause to be unresponsive to the user and just isn't an option.
Luckily, the folks at Microsoft has made it extremely easy to write the same code, but in an asynchronous manner. I usually use Tasks because I like the control you get over the operation as well as the ContinueWith() lets you control what you do with the result should you need to propagate data back to the calling thread. If you prefer to use threads, ThreadPool.QueueUserWorkItem is just as easy.
Any operation you do not want to block the UI thread wrap it like this,
Task.Factory.StartNew(() => Object.PerformOperation());
or
ThreadPool.QueueUserWorkItem(new WaitCallback((x) => Object.PeroformOperation()));
I find this allows me to write the same exact code, but without blocking the UI thread. If you have several statements to execute you can use a block as well.
Task.Factory.StartNew(() =>
{
// do something
// do more stuff
// done
}).ContinueWith((completedTask) =>
{
// if you were computing a value with the task
// you can now do something with it
// this is like a callback method, but defined inline
// use ui's dispatcher if you need to interact with ui compontents
UI.Label.Dispatcher.Invoke(new Action(() =>
UI.Item.Label.Text = completedTask.Result;
}
The upcoming async features that are being released in the next .net version actually streamline this even more! But since it uses tasks you will still want to get comfortable with using them.
// this will begin the operation, then return control back to the ui so it does not hang.
var result = await Object.PerformLongTask();
// once the long task is completed then it continues and you can use the result
UI.Item.Label = result;
To give a real example, here is some code from an FTP client I wrote which has has a WPF front end. When the start button is clicked the ftp transfer is launched in it's own task, then a while loop which updates the interface every half a second is launched in a task, so neither interferes with the interface thread. Again it's the same code, just wrapped in lambada's.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
ftp.Mirror(#"C:\LocalFolder", "/RemoteFolder", 10));
Task.Factory.StartNew(() =>
{
while (true)
{
lbPercentSuccess.Dispatcher.Invoke(new Action(() =>
{
lbPercentSuccess.Content = ftp.FtpProgress.SuccessPercentage;
lbPercentError.Content = ftp.FtpProgress.ErrorPercentage;
lbPercentTotal.Content = ftp.FtpProgress.TotalPercentage;
lbDuration.Content = ftp.FtpProgress.Duration;
}));
Thread.Sleep(500);
}
});
}
This is not possible to my knowledge. You can only run and invoke individual methods or queue them on separate threads when need be. Setting an actual object on a separate thread defeats your purpose. This is because you only going to harness the benefits of multithreading when invoking a method on a separate thread not an object.
then reassign the del to MethodTwo... and so on. This is made easier if you conform to a method signature.
Possible solution:
Thread threadTest = new Thread(new ThreadStart(MethodOne));
threadTest = new Thread(new ThreadStart(MethodTwo));
threadTest.Start();
Or
Action del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(null, null);
Func<int,int> del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(11,null, null);
int value = del.EndInvoke(result);
It's not simple, but have a look at this. It's a nice explination of how to use cross thread communication.
http://www.codeproject.com/KB/cs/delegatequeue.aspx
So far, this is what I found (from iPhone development). The Run loop acts like a spine that invokes various methods. It is implemented like the following:
A more elegant solution is welcomed.
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning)
{
if (_runSleepMilliSeconds != null)
{
_Sleep(_runSleepMilliSeconds ?? 3000);
_runSleepMilliSeconds = null;
}
}
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
private int? _runSleepMilliSeconds = null;
public void Sleep(int milliseconds)
{
_runSleepMilliSeconds = milliseconds;
}
private void _Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}