Windows forms, loops and threading - c#

I want to make server application. In the beginning it should make thread for organizing every connection and write logs in Listbox. I have problem because i don't know where can i make new thread which would have access to Form1.Listbox1. This is what i tried:
public class ServerLoop
{
Form1 form1;
public ServerLoop(Form1 f)
{
form1 = f;
}
public void loop()
{
form1.addConsoleMessage("test");
}
}
And Form1 class:
public partial class Form1 : Form
{
public Thread tServerLoop;
public ServerLoop serverLoop;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
console.Items.Clear();
players.Items.Clear();
players.Items.Add("Witaj w serwerze");
addConsoleMessage("test");
serverLoop = new ServerLoop(this);
tServerLoop = new Thread(serverLoop.loop);
tServerLoop.Start();
}
private void connectButton_Click(object sender, EventArgs e)
{
}
public void addConsoleMessage(String msg)
{
console.Items.Add(msg);
}
}
Anyone knows what can i do to acheive this?

Well, you could use Invoke to marshal a delegate back onto the UI thread where that ListBox can be safely accessed.
public void loop()
{
form1.Invoke(new Action(
() =>
{
form1.addConsoleMessage("test");
}));
}
But alas, this option is inferior. Actually, these marshaling techniques are generally terrible. Do not get me wrong. There is a time and place for Invoke (and the like), but this, like many situations, is not one of them.
The code is ugly because you have to sprinkle Invoke calls all over the place.
It forces you into a design where the UI thread and worker thread are tightly coupled.
The worker thread is dictating the update frequency of the UI.
It is inefficient.
It can flood the UI message queue (at least it could with BeginInvoke).
The worker thread has to wait for a response from the UI thread before it can proceed (it will with Invoke anyway).
So how would I solve this problem? Well, with the boring old System.Windows.Forms.Timer and the fancy new ConcurrentQueue<T> of course.
public partial class Form1 : Form
{
private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
console.Items.Clear();
console.Items.Add("test");
players.Items.Clear();
players.Items.Add("Witaj w serwerze");
Task.Factory.StartNew(
() =>
{
while (GetSomeCondition())
{
string value = GetSomeValue();
queue.Enqueue(value);
}
});
}
private void YourTimer_Tick(object sender, EventArgs e)
{
string value;
while (queue.TryDequeue(out value)
{
console.Items.Add(value);
}
}
}
So what do we have now.
It looks elegant.
Our background task knows only about a queue. The tight coupling has been broken.
The UI thread is now dictating the update frequency...the way it should be.
It is a lot more efficient.
There is no chance that the UI message queue will get flooded.
And finally, the worker can speed along merrily completely unware of what the UI thread is doing.
This solution is not completely devoid of disadvantages though. Now that we have our worker thread speeding along it is possible that it produces more items for the queue then what the UI thread can consume. It would not typically be a problem, but there are techniques for dealing with that.

Related

How to suspend a thread by another thread in C#?

Sorry for my bad English. Hope someone suggests me a better version of my question.
I've searched but seemed like I couldn't find the answer for my problem.
Currently, I'm writing a C# WPF app. This app will perform a heavy task in a long time. So I've decided to create another class with that heavy method and pass that method to another thread. I have to create a class to do that because the heavy method takes parameters.
I want the ability to suspend and resume that thread. I've known that I should use a ManualResetEvent object or Thread.Sleep method.
After many hours of trying and testing, getting confused why I always end up suspend the UI thread but the heavy thread is still running. What I've tried were:
Create a ManualResetEvent object called mre inside the HeavyClass. When user click the Pause button, the UI class will call the method heavyClass.mre.WaitOne().
class HeavyClass
{
// properties
ManualResetEvent mre = new ManualResetEvent(false);
public void HeavyRun()
{
//Do something takes really long time
//And doesn't have any loops
}
}
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
heavyClass.mre.WaitOne();
}
}
Create a method called SleepThread inside the HeavyClass. When user click the Pause button, the UI class will call the method heavyClass.SleepThread().
class HeavyClass
{
//properties
ManualResetEvent mre = new ManualResetEvent(false);
public void SleepThread()
{
Thread.Sleep(Timeout.Infinite);
//mre.WaitOne();
//They are the same behavior
}
public void HeavyRun()
{
//Do something takes really long time
//And doesn't have any loops
}
}
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
heavyClass.SleepThread();
}
}
Create an EventHandler<MainWindow> PauseThread inside the UI class, then write its handle inside the HeavyClass. When user click the Pause button, the UI class will trigger the event PauseThread(this, this).
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
public event EventHandler<MainWindow> PauseThread;
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
PauseThread(this, this);
}
}
class HeavyClass
{
// properties
ManualResetEvent mre = new ManualResetEvent(false);
public void HeavyRun()
{
MainWindow.PauseThread += (s, E) =>
{
Thread.Sleep(Timeout.Infinite);
//mre.WaitOne();
//They are the same behavior
};
//Do something takes really long time
//And doesn't have any loops
}
}
As I said above, I always paused the UI thread and the heavy task is still running.
And finally in the end, I've known the essence of my problem. That is: which thread calls Thread.Sleep() or WaitOne() will be blocked. Yeah, "which thread", not "which class".
Everything makes sense for me now. But that doesn't help me to achieve my goal. And that leads me to think that I am doing the seemingly impossible thing. It's clearly that I want to pause a thread by another thread. But that another thread is the one who calls any kinds of "suspend thread", so it is the one who is suspended. I don't have any idea about how to make the heavy method to be suspended by itself. It is running, how the hell it could know when the user click the Pause button?
I am at a total loss. Someone please help me to make my app works as expected.
By the way, this impossible thing makes me think that I am doing things wrong way, is it?
UPDATE: If you like to see my heavy task, actually it is very simple
class HeavyClass
{
public string filePath = "D:\\Desktop\\bigfile.iso";//This file is about 10GB
public string HeavyRun()
{
string MD5Hash;
MD5 md5 = MD5.Create();
Stream stream = File.OpenRead(filePath);
MD5Hash = Encoding.Default.GetString(md5.ComputeHash(stream));
return MD5Hash;
}
}
To make a thread suspendable, the work in the thread must be separable. In your case md5.ComputeHash(stream) will do all the work, and there is not way to make sure that thread will suspend at a right(saft) point inside md5.ComputeHash(stream). So you have to rewrite HeavyClass like below. Please notice that those codes are not the best approach of handling a thread, and I just try to keep it as same as the original.
class HeavyClass
{
MD5 _md5 = MD5.Create();
MethodInfo _hashCoreMI = _md5.GetType().GetMethod("HashCore", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo _HashFinalMI = _md5.GetType().GetMethod("HashFinal", BindingFlags.NonPublic | BindingFlags.Instance);
WaitHandle _signal;
public void HeavyClass(WaitHandle signal)
{
_signal = signal;
}
public string HeavyRun(string filename)
{
byte[] buffer = new byte[4096];
int bytesRead = 0;
_signal.Set();
using(FileStream fs = File.OpenRead(filename))
{
while(true)
{
bytesRead = fs.Read(buffer, 0, 4096);
if (bytesRead > 0)
{
_hashCoreMI.Invoke(_md5, new object[] { buffer, 0, bytesRead });
}
else
{
break;
}
// if WaitHandle is signalled, thread will be block,
// otherwise thread will keep running.
_signal.WaitOne();
}
}
byte[] hash = _hashFinalMI.Invoke(_md5, null);
_md5.Initialize();
return Encoding.ASCII.GetString(hash);;
}
}
class MainWindow : Window
{
private HeavyClass _heavyClass;
private ManualResetEvent _mre;
public MainWindow()
{
InitializeComponent();
_mre = new ManualResetEvent(true);
_heavyClass = new HeavyClass(_mer);
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun("D:\\Desktop\\bigfile.iso"));
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
_mre.Reset();
}
private void buttonResume_Click(object sender, RoutedEventArgs e)
{
_mre.Set();
}
}

Thread updating GUI freezes in random moments

I have form with button and text box. Button is starting thread which is updating value of text box.
public Form1()
{
InitializeComponent();
myDelegate = new UpdateUi(updateUi);
}
private void button1_Click(object sender, EventArgs e)
{
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
private void updateUi(int i)
{
textBox1.Text = i.ToString();
Thread.Sleep(1000);
}
public Thread myThread;
public delegate void UpdateUi(int i);
public UpdateUi myDelegate;
and ThreadClass:
public class MyThreadClass
{
Form1 myFormControl1;
public MyThreadClass(Form1 myForm)
{
myFormControl1 = myForm;
}
public void Run()
{
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle.
for(int i=0;i<100;i++)
{
if(myFormControl1.InvokeRequired)
{
myFormControl1.Invoke(myFormControl1.myDelegate,i);
}
}
}
}
As You can see there is nothing special in my code but sometimes the code freeze.
eg it goes 1->2->3->freeze->16->17 and so on.
I took code from HERE with little modifications
The issue is you are delaying the UI thread not the the process itself so what happens is you issue all the update commands but since it all runs on the same thread it gets clogged because the Thread.Sleep stops the UI thread so it runs a bunch of textBox1.Text = i.ToString(); then it stops for all the time of all the Thread.Sleep(1000); probably the number of 1->2->3... you see is equal to the number of cores in your machine.
When you stop the run method what happens is you issue one update command that runs immediately and wait for one second until you issue the next command witch I think its what you are trying to accomplish.

Communication between threads via delegates?

I am looking for a solution for interthread communication.
Thread A is the main thread of a windows app. I starts a Thread B that is working independant of thread a, they do not share code. But thread A has to get some feedback about status of thread b. I try to solve this with a delegate.
I am very sorry, I forgot to add that I have to work on .net 3.5, c#, WEC7
It is important that the code
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
is executed in context of thread a, how can I achieve this
public partial class Form1 : Form
{
//...
public void StartThread(Object obj)
{
new ClassForSecondThread(obj as Parameters);
}
private void button1_Click(object sender, EventArgs e)
{
//ParameterizedThreadStart threadstart = new ParameterizedThreadStart(startThread);
ParameterizedThreadStart threadstart = new ParameterizedThreadStart(StartThread);
Thread thread = new Thread(threadstart);
Parameters parameters = new Parameters(){MyEventHandler = OnMyEvent};
thread.Start(parameters);
}
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
}
//This code is executed in Thread B
public class ClassForSecondThread
{
public ClassForSecondThread(Parameters parameters)
{
if (parameters == null)
return;
MyEventhandler += parameters.MyEventHandler;
DoWork();
}
private void DoWork()
{
//DoSomething
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World");// I think this should be executed async, in Thread A
Thread.Sleep(10000);
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World again"); // I think this should be executed async, in Thread A
}
public event MyEventHandler MyEventhandler;
}
public class Parameters
{
public MyEventHandler MyEventHandler;
}
public delegate void MyEventHandler(string foo);
As you want to call the MessageBox on the main UI thread, you can achieve what you want using Control.Invoke.
Invoke((MethodInvoker)(() => MessageBox.Show(foo)));
The Invoke method can be called directly on the Form and you won't be in the context of Thread B within the delegate - the code will run on the same thread as the Form.
EDIT:
OP question: if I understood Control.Invoke correctly, it always acts in the context of a control?
Although the Invoke method uses a Control (in this case the form) to get a handle to the UI thread it is running on, the code within the delegate is not specific to the UI. If you want to add more statements and expand it to include more stuff, just do this:
string t = "hello"; //declared in the form
//Thread B context - Invoke called
Invoke((MethodInvoker)(() =>
{
//Back to the UI thread of the Form here == thread A
MessageBox.Show(foo);
t = "dd";
}));
Also, if you are updating things in a multi threaded environment where the data is accessible to more than one thread, then you will need to investigate sychronization - applying locks to data etc.
For what it is worth you can simplify your code considerably by using the new async and await keywords in C# 5.0.
public class Form1 : Form
{
private async void button1_Click(object sender, EventArgs args)
{
OnMyEvent("Hello World");
await Task.Run(
() =>
{
// This stuff runs on a worker thread.
Thread.Sleep(10000);
});
OnMyEvent("Hello World again");
}
private void OnMyEvent(string foo)
{
Message.Show(foo);
}
}
In the code above OnMyEvent is executed on the UI thread in both cases. The first call be executed before the task starts and the second call will be executed after the task completes.

Closing a form that is created in another thread

I have been searching for an answer to my particular problem for a while with no success.
I have a task in my program that takes a few seconds and I want to show a new form while that task is being done. The new form has a loadingbar and some text.
I need to show the new form parallel to the task otherwise the task will not start untill I close the new form.
This is the solution I have now:
private void loadingBar()
{
frmLoading frm = new frmLoading("Please wait while the database is being backed up", "This might take several days.");
frm.ShowDialog();
}
public void Backup()
{
Thread load = new Thread(new ThreadStart(loadingBar));
load.Start();
///Execute a task.
load.Abort();
}
So, this works OK but my question is: Wouldn't it be better to close the the form "frm" in the load-thread to make it stop?
You could do this a few ways...
1 - You could do as BendEg suggested and invoke you frmClose once you are ready
Something like;
Invoke(new Action(Close));
or
Invoke(new Action(() => frmMain.Close()));
2 - Or you could simply use a background worker;
The simplest way to demonstrate this would be to add a BackgroundWorker to your form, and use the events provided;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
MessageBox.Show(#"Please wait while the database is being backed up", #"This might take several days.");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Debug.WriteLine("Running"); //Execute a task
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.WriteLine("Ended"); //Dispose of any objects you'd like (close yor form etc.)
}
I hope this helps.
You can declare the form on Class-Level and later close it with an invoke.
MSDN-Windows Forms Invoke
Like this:
public class Class1
{
private Form myForm;
public Class1()
{
myForm = new Form();
}
public void DoSomeWork()
{
// ===================================================
// Do Some Work...
// ===================================================
myForm.Invoke(new MethodInvoker(this.Hide));
}
public void Hide()
{
myForm.Hide();
}
public void Backup()
{
myForm.ShowDialog();
Thread load = new Thread(new ThreadStart(DoSomeWork));
load.Start();
}
}
I think this can work for you.
void YourMethod()
{
WaitForm wf = new WaitForm();
Invoke(new PleaseWaitDelegate(Launch),wf);
bool val = BoolMethodDoWork();
Invoke(new PleaseWaitDelegate(Close), wf);
if(val)
{
MessageBox.Show("Success!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
return;
}
MessageBox.Show("Damn!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
delegate void PleaseWaitDelegate(Form form);
void Launch(Form form)
{
new System.Threading.Thread(()=> form. ShowDialog()).Start();
}
void Close(Form form)
{
form.Close();
}
I think this will help you (if i understood you right):
Parallel.Invoke(() => somemethod(), () =>
{
someothertaskmethod();
});
I placed methods as example to demonstrate 2 tasks running.
You nee to use the proper using statement using System.Threading.Tasks;

Why is this code making my form disappear?

Since I added a splash screen my main form will sometimes (about 1 every 20 times) disappear like it's minimized (it will be invisible but it will be still on the task bar and if I click it it reappears). Here is my code:
static class Program
{
private static SplashScreen splashScreen = null;
private static ManualResetEvent splashScreenWaiter = null;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ShowSplashAsync();
BuilderForm2 builderForm2 = new BuilderForm2();
builderForm2.Shown += new EventHandler(builderForm2_Shown);
Application.Run(builderForm2);
}
private static void HideSplash()
{
if (splashScreenWaiter != null)
{
splashScreenWaiter.WaitOne();
splashScreen.Invoke(new Action(splashScreen.Close));
splashScreenWaiter = null;
splashScreen = null;
}
}
private static void builderForm2_Shown(object sender, EventArgs e)
{
HideSplash();
}
private static void ShowSplashAsync()
{
splashScreenWaiter = new ManualResetEvent(false);
Thread splashThread = new Thread(ShowSplash);
splashThread.IsBackground = true;
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start(splashScreenWaiter);
}
private static void ShowSplash(object resetEvent)
{
splashScreen = new SplashScreen((ManualResetEvent)resetEvent);
Application.Run(splashScreen);
}
}
And this is SplashScreen code:
public partial class SplashScreen : Form
{
private ManualResetEvent ResetEvent;
bool handleCreated = false;
bool formShown = false;
public SplashScreen(ManualResetEvent resetEvent)
{
ResetEvent = resetEvent;
HandleCreated += new EventHandler(SplashScreen_HandleCreated);
InitializeComponent();
}
private void SetResetEventIfReady()
{
if(handleCreated && formShown) ResetEvent.Set();
}
private void SplashScreen_Shown(object sender, EventArgs e)
{
formShown = true;
SetResetEventIfReady();
}
void SplashScreen_HandleCreated(object sender, EventArgs e)
{
handleCreated = true;
SetResetEventIfReady();
}
}
Nothing jumps out. There is however a very serious race condition in your code. It is related to the SystemEvents class. That class provides important notifications to controls so they can respond to the user changing the Windows theme. That class needs a hidden notification window to receive messages about the changes the user made.
This goes very wrong if your program's first window is created on a worker thread instead of the UI thread. That makes the SystemEvents class create that notification window on the wrong thread (not your worker thread btw). And the events it raises will be called from that thread. Getting the event on that wrong thread creates havoc, controls are not thread-safe. The most typical outcome is that you'll have odd painting problems or the form deadlocks when you lock the workstation. I can imagine what you see going wrong could be explained by this as well.
The .NET framework already has excellent and time-tested support for splash screens. I recommend you use it instead of spinning your own. Check this answer for the code.
If you want to keep your own then you can work around the race problem by pasting this line of code into your Main method, before the ShowSplashAsync call:
Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };

Categories