views:

649

answers:

8

Hello, 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.

A: 

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.

I do not know if it is what you asked for. I need to do sth like this: for instance I have 2 threads and 1 textBox to write in, after threads start, Im checking textBox Text Length and doing it after 5 sec to check if the textBox is free, if yes, Im writing in it random numbers in radom time, while 1 thread is using textBox, other one should do as the first one and check if textBox is free, if not, he should sleep for a random time and after that check it again.
Allek
A: 

This MSDN Article explains how to make thread safe calls to windows form controls.

Brandon
A: 

You can only access GUI components from the main thread. To write to a textbox from another thread, you need to use BeginInvoke().

Jon B
A: 

Well, almost have what Ive been looking for, thank you. I would like to ask now about thread restrting, is there a simple way to do that ?

            for (int i = 0; i <= 20; i++)
            {
                //labelOne.Text = "Working ...";
                Thread.Sleep(1000);
                textBox.BeginInvoke(new Write(UpdateText), new object[] { i.ToString() });
            }

What should I do to restart it after finishing the loop ?

Allek
+1  A: 

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();
    }
}
Jeff Youel
+1  A: 

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.

Joe.Ingalls
+1  A: 

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;
        }
    }
JDunkerley
A: 

I found it very helpful and to the point

Embiza Tadesse