I have an MFC application which is composed of multiple threads, but the problem is with a specific two.
The first thread (CGuiThread) is responsible for GUI (it's not the main thread) and contains a window object (CMainWindow), which contains an inner window object (CInnerWindow), which displays multiple progress displays and has a scroll bar.
The second thread (CStatusDispatcherThread) is responsible for sending to the gui thread messages, which contain progress status information related to some calculation processes.
Once the calculations begin, the status dispatcher sends messages with the status to the GUI thread. The gui thread updates progress bars in the inner window accordingly.
The problem starts when I move or hold the thumb of the inner window's scroll bar - it seems that GUI thread stops processing the status messages from the status dispatcher thread, since the progress bars are no longer updated. Not only that, I'd expect the status messages to be stopped somewhere and processed once I release the tumb, but it is not happening. New messages arrive but the messages that while clicking are lost.
If anyone has an idea what could be the cause, I would be very grateful.
I tried "catching" the status messages in the CGuiThread::PreaTranslateMessage function, but it seems that after holding the scroll thumb, they no longer get there, even though PostThreadMessage of CStatusDispatcherThread indicates they were sent successfully.
#define MY_MESSAGE 1
class CStatusDispatcherThread : public CWinThread
{
//...
// This class sends progress status percentaget to gui thread via PostThreadMessage
OnTimer(UINT nIDEvent)
{
PostThreadMessage(iThreadID,MY_MESSAGE,100,0);
}
};
class CGuiThread : public CWinThread
{
//...
BEGIN_MESSAGE_MAP(CGuiThread, CWinThread)
ON_THREAD_MESSAGE(MY_MESSAGE,OnStatusMessage)
END_MESSAGE_MAP()
private:
CMyMainWindow m_mainWindow;
void OnStatusMessage(WPARAM iStatus, LPARAM dummy);
{
m_mainWindow.updateStatus((int)iStatus)
}
};
class CMyMainWindow : public CWnd
{
//...
void updateStatus(int iStatus)
{
m_sbarWindow.updateStatusBar(iStatus);
}
private:
CInnerWindow m_sbarWindow;
};
class CInnerWindow : public CWnd
{
//...
void updateStatusBar(int iStatus)
{
//...
}
private:
BOOL Create(...)
{
CWnd::Create(strClassName, strWindowTitle, WS_DLGFRAME | WS_CHILD| WS_VISIBLE | WS_VSCROLL,
rectRectOfWnd, pParentWnd, iID, NULL);
}
void OnVScroll(nSBCode, nPos, pScrollBar)
{
//...
}
};
Thank in advance,
Gal
It is documented to fail. From the MSDN page on PostThreadMessage:
if the recipient thread is in a modal loop (as used by MessageBox or
DialogBox), the messages will be lost.
Holding down the scroll slider creates such a modal loop. You can eliminate the problem by posting to an HWND, not to a thread ID.
The only thread that is allowed to update the GUI is the main thread. Otherwise you'll end up with unpredicted behavior.
Related
A toggle button in a JavaFX operation will be accessed by 2 separate threads.
1.
One thread will be invoked as soon as user clicks (toggles button state) and will
a) do something in the OS
b) check if (a) succeeded
c) exit on success / exit and return toggle button to previous state on failure
2
The other thread will monitor events asynchronous to the previous operation(s) and in case of a particular event it will change the button state.
Do I need to provide synchronization between threads 1 and 2 in terms of locking the button state?
EDIT: The idea proposed by James_D seems reasonable, but I just wanted to propose an alternative (whose effectiveness remains to be proved however).
How about using synchronized code blocks, and using as lock the reference to the particular button, i.e. something like:
// getting the reference to the button
#FXML
private ToggleButton tButtonToBeSynchronized
// Thread1
synchronized(tButtonToBeSynchronized) {
// do stuff with button upon user click
}
// Thread2
synchronized(tButtonToBeSynchronized) {
// poll system every X seconds
// when asynchronous event occurs (not related to UI events)
// update tButtonToBeSynchronized state
}
Would that work in case these are called by different Controller classes? (assuming the reference to the tButtonToBeSynchronized is passed by reference - and not by value by the FXML framework?
Like most UI toolkits, JavaFX assumes a single threaded model. You should only ever access the state of nodes that are part of a scene graph from the FX Application Thread. So, toggling a button is not an atomic operation, and the code you describe is not guaranteed to work as you currently have it set up. In Java 8, it will likely throw a RuntimeException.
JavaFX provides functionality to enable interoperability with background threads. The lowest level of these is Platform.runLater(Runnable r), which executes r on the FX Application Thread. So, your monitor thread (item 2 in your question) should change the state of the toggle button with
Platform.runLater( () -> toggleButton.setSelected(...) );
There is also a javafx.concurrent API. This provides a Task class, among others, which acts as both a Runnable and a java.util.concurrent.FutureTask, and additionally has a collection of callback methods for submitting code to be executed on the FX Application Thread at various points in the Task's lifecycle.
So you should implement item 1 in your question as:
ExecutorService exec = ... ; // e.g. Executors.newCachedThreadPool();
toggleButton.selectedItemProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
// do something on OS
// throw exception if failed
return null ;
}
};
task.setOnFailed(event -> toggleButton.setSelected(wasSelected));
exec.submit(task);
}
});
If you prefer to return a value indicating success or failure, you can do
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
// do work...
boolean successful = ... ;
return successful ;
}
};
task.setOnSucceeded( event -> {
boolean wasSuccessful = task.getValue();
// ...
});
I created an application in which I would like to add a loading screen when the application is opening a project because the loading of the project can be long and sometimes, the gui blocks so the user can think there is a crash.
So I tried with QThread, reading doc and "solved" examples on this forum but nothing to do, I can't make it work.
I have a MainWindow class which deals with GUI and this class is the one I create in the main function :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Then I have :
mainwindow.h
class MyThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
...
private :
Controller *controller;//inherits from QObject and loads the project
QList<MyThread*> threads;
public slots :
void animateLoadingScreen(int inValue);
}
mainwindow.cpp
MainWindow::MainWindow(...)
{
controller=new Controller(...);
threads.append(new MyThread(30, this));
connect(threads[0], SIGNAL(valueChanged(int)), this, SLOT(animateLoadingScreen(int)));
}
void MainWindow::animateLoadingScreen(int inValue)
{
cout<<"MainWindow::animateLoadingScreen"<<endl;
widgetLoadingScreen->updateValue(inValue);//to update the animation
}
void MainWindow::openProject()
{
widgetLoadingScreen->show()://a widget containing a spinner for example
threads[0]->start();//I want to launch the other thread here
controller->openProject();
threads[0]->exit(0);//end of thread so end of loading screen
}
MyThread.h
class MyThread : public QThread
{
Q_OBJECT;
public:
explicit MyThread(int interval, QObject* parent = 0);
~MyThread();
signals:
void valueChanged(int);
private slots:
void count(void);
protected:
void run(void);
private:
int i;
int inc;
int intvl;
QTimer* timer;
};
MyThread.cpp
MyThread::MyThread(int interval, QObject* parent): QThread(parent), i(0), inc(-1), intvl(interval), timer(0)
{
}
void MyThread::run(void)
{
if(timer == 0)
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(count()));
}
timer->start(intvl);
exec();
}
void MyThread::count(void)
{
if(i >= 100 || i <= 0)
inc = -inc;
i += inc;
emit valueChanged(i);
}
When I execute the app, and click on open button which launches MainWindow::openProject(), I get :
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyThread(0x5463930), parent's thread is QThread(0x3cd1f80), current thread is MyThread(0x5463930)
MainWindow::animateLoadingScreen
MainWindow::animateLoadingScreen
....
MainWindow::animateLoadingScreen
MainWindow::animateLoadingScreen
(and here the controller outputs. and no MainWindow::animateLoadingScreen anymore so the widget loading screen is never animated during the opening of the project)
So what do I have to do, what do I have to put in MyThread class, how to link its signal to MainWindow to update the loading screen. And I think that there may be a problem with widgetLoadingScreen which is created in MainWindow so if MainWindow is blocked beacause of the opening, the widgetLoadingScreen can't be updated since it is in the thread of MainWindow which handles the GUI ?!
I read :
http://www.qtcentre.org/wiki/index.php?title=Updating_GUI_from_QThread
but with that one, I got error message at runtime, it's the one I use in the code I give above
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyThread(0x41938e0), parent's thread is QThread(0x1221f80), current thread is MyThread(0x41938e0)
I tried that too :
How to emit cross-thread signal in Qt?
but, even if I don't have the error message at runtime, it's the same for the animation which is not updated.
I am completely lost, and I don't think it's something difficult to do to have a loading screen in a thread while the main thread is opening a project?!
Qt has a QSplashScreen class which you could use for a loading screen.
Besides this, one of the problems you have is due to thread affinity (the thread in which an object is running) and the fact that you've decided to inherit from QThread.
In my opinion, QThread has a misleading name. It's more of a thread controller and unless you want to change how Qt handles threads, you really shouldn't inherit from it and many will tell you that "You're doing it Wrong!"
By inheriting QThread, your instance of MyThread is running on the main thread. However, when a call to exec() is made, it starts the event loop for the new thread and all its children, which includes the QTimer, and tries to move it to the new thread.
The correct way to solve this is not to inherit from QThread, but to create a worker object, derived from QObject and move it to the new thread. You can read about how to 'Really Truly Use QThread' here.
1st problem - runtime error with QTimer
Problem is in void MyThread::run(void), line timer = new QTimer(this);. The thread instance is created in (and so owned by) different (main) thread then it represents. For this reason, you cannot use thread as parent for object created inside the thread. In your case, solution is simple - create the timer on stack.
Example:
void MyThread::run(void)
{
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(count()));
timer.start(intvl);
// Following method start event loop which makes sure that timer
// will exists. When this method ends, timer will be automatically
// destroyed and thread ends.
exec();
}
2nd problem - GUI not updating
Qt requires the GUI to be created and displayed from main application thread. This means that blocking main thread with big operation blocks whole GUI. There are only 2 possible solutions:
Move the heavy work to other (loading) thread. This is best solution and I believe it's worth the effort (I'm aware you wrote that this would be problematic).
During the heavy operation, call regularly QCoreApplication::processEvents() - each time you call this, events will be processed, which includes calling slots, key and mouse events, GUI redraw etc. The more often you call this, the more responsive GUI will be. This is simpler to implement (just put one line all over the code), but it's quite ugly and if the operation blocks on loading a file, the GUI will freeze for some time. That means that responsiveness of your GUI depends on interval between calls. (But if you call it too often, you will slow down the loading progress.) This technique is discouraged and it's best to avoid it...
The way I will do it based on the default example on Qthread Page:
Break the big controller->openProject(); such that it updates a variable
provide access to that variable using a signal ( like statusChanged(int)).
Do what you need to do once the signal is triggered.
The code looks like
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
private:
int status; //
bool hasworktoDo();
void doSmallWork();
public slots:
void doWork() {
while(hasworktoDo())
{
doSmallWork(); // fragments of controller->openProject();
++status; //previously set to 0
emit statusChanged(status);
}
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
void statusChanged(int value);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(statusChanged(int)), this, SLOT(updateStatus(int)));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate()), worker, SLOT(doWork()));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
void updateStatus(int value)
{
int status = value;
//now you have what to use to update the ui
}
signals:
void operate(); //
};
If you have trouble breaking the openProject operations in small parts, it just mean it is pointless to say on the UI that you are at 50%... Just say Loading... and make the code simpler. Note that you don't need a timer in my case, as the worker sends regular updates
I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue
I have created an abstract base class to allow for multiple implementation of a task, which can be called generically via MFC dialog. This task needs to be able to be interrupted if the user clicks cancel.
abstract_dll.h:
class abstract_dll
{
public:
virtual void my_task(CFeedback *fb)=0;
}
Where CFeedback is an abstract class to control user feedback (ie. progress bar)
concrete_dll.h:
class concrete_dll
{
virtual void my_task(CFeedback *fb)
{
//do some work
//step progress bar
boost::this_thread::interruption_point();
//do some work
//step progress bar
boost::this_thread::interruption_point();
}
}
extern "C" abstract_dll* get_class() { return new concrete_dll(); }
Now within the MFC Dialog I load the appropriate concrete_dll and initialize my abstract_dll *dll = module->get_class();
Then start a new boost::thread which calls the dll->my_task(fb);
Then when I call thread.interrupt(). The thread is never interrupted, and it never excepts at my interruption_points. I have traced the thread ID it is the same until we're in the concrete_dll implementation, then I just get 0x0000 for the thread id.
Any thoughts? PS. The code above is just pseudo code for what I have. My actual code compiles and runs, I just can't get it to interrupt.
I think the answer to your question is here:
http://lists.boost.org/boost-users/2010/01/55171.php
In short: you need to link to DLL version of boost:threads both in your project and DLL. Just put the:
#define BOOST_THREAD_USE_DLL
before <boost/thread.hpp> inclusion (or in the project propeties)
BR
I'm testing my app with mono in prevision of a Linux port, and I have a threading problem. I initially considered pasting 3000 code lines here, but finally I've devised a small minimal example ;)
You have a form with a button (poetically named Button1, and a label (which bears, without surprise, the name Label1)). The whole lot is living a happy life on a form called Form1. Clicking Button1 launches an infinite loop that increments a local counter and updates Label1 (using Invoke) to reflect its value.
Now in Mono, if you resize the form, the label stops updating, never to restart. This doesn't happen with MS implementation. BeginInvoke doesn't work any better; worse, it makes the UI hang in both cases.
Do you know where this discrepancy comes from? How would you solve it? And finally, why doesn't BeginInvoke work here? I must be making a huge mistake... but which?
EDIT:
Some progress so far:
Calling BeginInvoke does in fact work; only, the UI just doesn't refresh fast enough, so it seems to stop.
On mono, what happens is that the whole thread hangs when you insert a message in the UI queue (eg by resizing the form). In fact, the synchronous Invoke call never returns. I'm trying to understand why.
Of interest: even using BeginInvoke, the asynchronous calls don't get executed before the resizing operation ends. On MS.Net, they keep running while resizing.
The code looks like this (C# version lower):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim T As New Threading.Thread(AddressOf Increment)
T.Start()
End Sub
Sub UpdateLabel(ByVal Text As String)
Label1.Text = Text
End Sub
Delegate Sub UpdateLabelHandler(ByVal Text As String)
Sub Increment()
Dim i As Long = 0
Dim UpdateLabelDelegate As New UpdateLabelHandler(AddressOf UpdateLabel)
Try
While True
i = (i + 1) Mod (Long.MaxValue - 1)
Me.Invoke(UpdateLabelDelegate, New Object() {i.ToString})
End While
Catch Ex As ObjectDisposedException
End Try
End Sub
End Class
Or, in C#,
public class Form1
{
private void Button1_Click(System.Object sender, System.EventArgs e)
{
System.Threading.Thread T = new System.Threading.Thread(Increment);
T.Start();
}
public void UpdateLabel(string Text)
{
Label1.Text = Text;
}
public delegate void UpdateLabelHandler(string Text);
public void Increment()
{
long i = 0;
UpdateLabelHandler UpdateLabelDelegate = new UpdateLabelHandler(UpdateLabel);
try {
while (true) {
i = (i + 1) % (long.MaxValue - 1);
this.Invoke(UpdateLabelDelegate, new object[] { i.ToString() });
}
} catch (ObjectDisposedException Ex) {
}
}
}
This is a bug in the mono runtime, at least I think it is. The code might not be good practice (I'm not a threading expert), but the thing that suggests a bug is the fact that the behaviour differs on windows and Linux.
On Linux, mono has exactly the same behaviour as MS.Net has on windows. No hanging, continuous updates even while resizing.
On Windows, mono displays all the aforementioned problems. I've posted a bug report at https://bugzilla.novell.com/show_bug.cgi?id=690400 .
Do you know where this discrepancy
comes from? How would you solve it?
I am not sure. I do not see anything obvious in your code that would cause the difference between Mono and .NET. If I had to make a wild guess I would say there is a possibility that you have stumbled upon an obscure bug in Mono. Though, I suppose it is possible that Mono uses a sufficiently different mechanism for handling the WM_PAINT messages that cause the form to get refreshed. The constant pounding of the UI thread from repeated calls to Invoke may be disrupting Mono's ability to get the form refreshed.
And finally, why doesn't BeginInvoke
work here?
Calling Invoke in a tight loop is bad enough, but BeginInvoke will be even worse. The worker thread is flooding the UI message pump. BeginInvoke does not wait until the UI thread has finished executing the delegate. It just posts the requests and returns quickly. That is why it appears to hang. The messages that BeginInvoke is posting to the UI message queue keep building up as the worker thread is likely severely out pacing the UI thread's ability to process them.
Other Comments
I should also mention that the worker thread is nearly useless in the code. The reason is because you have a call to Invoke on every iteration. Invoke blocks until the UI has finished executing the delegate. That means your worker thread and UI thread are essentially in lock-step with each other. In other words, the worker is spending most of its time waiting for the UI and vice versa.
Solution
One possible fix is to slow down the rate at which Invoke is called. Instead of calling it on every loop iteration try doing it every 1000 iterations or the like.
Any even better approach is to not use Invoke or BeginInvoke at all. Personally, I think these mechanisms for updating the UI are way overused. It is almost always better to let the UI thread throttle its own update rate especially when the worker thread is doing continuous processing. This means you will need to place a timer on the form and have it tick at the desired refresh rate. From the Tick event you will probe a shared data structure that the worker thread is updating and use that information to update the controls on the form. This has several advantages.
It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
First and foremost: clicking on Button1 is asynchronous already, so you don't need to create another thread to increment, just call the increment method Sorry, I was reading your question line by line and by the time I got to the while-loop I forgot about the button:
private void Button1_Click(System.Object sender, System.EventArgs e)
{
Thread t = new Thread(Increment);
t.IsBackground = true;
t.Start();
}
Second: if you do need to use a thread then you should always set your thread to background (i.e. foreground prevents your process from terminating), unless you have a good reason for using a foreground thread.
Third: if you're making updates to the UI, then you should check the InvokeRequired property and call BeginInvoke:
public void UpdateLabel(string Text)
{
if (InvokeRequired)
{
BeginInvoke(new UpdateLabelDelegate(UpdateLabel), Text);
}
else
{
Label1.Text = Text;
}
}
public void Increment()
{
int i = 0;
while(true)
{
i++; // just incrementing i??
UpdateLabel(i.ToString());
Thread.Sleep(1000);// slow down a bit so you can see the updates
}
}
You can also "automate" the Invoke Required "pattern": Automating the InvokeRequired code pattern
And now see if you're still having the same problem.
I tried it on my machine and it works like a charm:
public partial class Form1 : Form
{
private delegate void UpdateLabelDelegate(string text);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(Increment);
t.IsBackground = true;
t.Start();
}
private void UpdateLabel(string text)
{
if (label1.InvokeRequired)
{
BeginInvoke(new UpdateLabelDelegate(UpdateLabel), text);
}
else
{
label1.Text = text;
}
}
private void Increment()
{
int i = 0;
while (true)
{
i++;
UpdateLabel(i.ToString());
Thread.Sleep(1000);
}
}
}