Problem with threading in C#

Hi,
I'm new to C# programming,that's why I have a lot to learn.I'm trying to understand how to create and work with threads in C#.Here's the code of my demo project.Please if somebody can see this code and help me to understand why I get an error when I start the code.The app stops after a while and show me an error that I don't understand and don't know how to fix it.
Please if somebody can help me I'll be very happy and thankful.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace ThreadsProblem
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid dataGrid1;
private System.Data.DataSet dataSet1;
private System.Data.DataTable dataTable1;
private System.Data.DataColumn dataColumn1;
private System.Data.DataColumn dataColumn2;
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

private bool bStartThread = false;
private Thread thread ;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
this.thread = new System.Threading.Thread( new ThreadStart(StartThread) );
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.dataSet1 = new System.Data.DataSet();
this.dataTable1 = new System.Data.DataTable();
this.dataColumn1 = new System.Data.DataColumn();
this.dataColumn2 = new System.Data.DataColumn();
this.button1 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.dataSet1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.dataTable1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.DataSource = this.dataTable1;
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(40, 32);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(200, 336);
this.dataGrid1.TabIndex = 0;
//
// dataSet1
//
this.dataSet1.DataSetName = "NewDataSet";
this.dataSet1.Locale = new System.Globalization.CultureInfo("bg-BG");
this.dataSet1.Tables.AddRange(new System.Data.DataTable[] {
  this.dataTable1});
//
// dataTable1
//
this.dataTable1.Columns.AddRange(new System.Data.DataColumn[] {
  this.dataColumn1,
  this.dataColumn2});
this.dataTable1.Constraints.AddRange(new System.Data.Constraint[] {
  new System.Data.UniqueConstraint("Constraint1", new string[] {
   "Column1"}, true)});
this.dataTable1.PrimaryKey = new System.Data.DataColumn[] {
  this.dataColumn1};
this.dataTable1.TableName = "Table1";
//
// dataColumn1
//
this.dataColumn1.AutoIncrement = true;
this.dataColumn1.Caption = "ID";
this.dataColumn1.ColumnName = "Column1";
this.dataColumn1.DataType = typeof(int);
//
// dataColumn2
//
this.dataColumn2.Caption = "Text";
this.dataColumn2.ColumnName = "Column2";
//
// button1
//
this.button1.Location = new System.Drawing.Point(592, 48);
this.button1.Name = "button1";
this.button1.TabIndex = 1;
this.button1.Text = "Strart thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(728, 381);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.dataSet1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.dataTable1)).EndInit();
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
if (! this.bStartThread )
{
this.bStartThread = true;
this.button1.Text = "Stop Thread";
this.thread.Start();
}
else
{
this.bStartThread = false;
this.button1.Text = "Start Thread";
}
}

private void StartThread()
{
while ( this.bStartThread )
{
Thread.Sleep(500);
DataRow dr = this.dataSet1.Tables["Table1"].NewRow();
this.dataSet1.Tables["Table1"].Rows.Add( dr );
dr.BeginEdit();
dr["Column2"] = "test "+dr["Column1"].ToString();
dr.AcceptChanges();
dr.EndEdit();
}
}
}
}


Answer this question

Problem with threading in C#

  • Umeshnath

    There are another couple of problems:

    When the button is clicked to stop the thread, then the while loop in StartThread() exits, and the thread terminates.

    It looks like you're using bStartThread to control the non-UI thread, with the intention that it continues running. If so, you should enclose the code in StartThread in an infinite loop:

    while( true )
    {
        while( this.bStartThread )
        {
           Thread.Sleep(500);
           // invoke a delegate on the form to update dataSet.
        }
    }

    and only Start the thread if its IsAlive property is false.

    Otherwise, if your intention is to allow the thread to stop when clicking the button, then you've got more work to do:

    You should Join() the thread after setting bStartThread to false, otherwise the user could click the button (if they're a fast clicker!) to start the thread again before it had finished terminating and you'd be attempting to Start a thread that is still in the started state.

    You can't Start a terminated thread, so you'd have to go ahead and create a new thread instance each time.







  • Juice Johnson

    Hi,Daniel,
    Thank you for the advise and this helpful links.
    This was very usefil to me to fix the problem.

    :-)

  • AJMurray

    Here's some code that does the two cases I described:

            [STAThread]
            static void Main()
            {
                Application.Run(new Form1());
            }

            public delegate void AddRowDelegate();

            private void AddRow()
            {
                DataRow dr = this.dataSet1.Tables["Table1"].NewRow();
                this.dataSet1.Tables["Table1"].Rows.Add( dr );
                dr.BeginEdit();
                dr["Column2"] = "test "+dr["Column1"].ToString();
                dr.AcceptChanges();
                dr.EndEdit();
            }

            // Code below for creating a new thread each time

            private void button1_Click(object sender, System.EventArgs e)
            {
                if (! this.bStartThread )
                {
                    this.bStartThread = true;
                    this.button1.Text = "Stop Thread";
                    this.thread = new System.Threading.Thread( new ThreadStart(StartThread) );
                    this.thread.Name = "Test";
                    this.thread.IsBackground = true;
                    this.thread.Start();
                }
                else
                {
                    this.bStartThread = false;
                    this.button1.Text = "Start Thread";
                    while (this.thread.ThreadState == ThreadState.Running || this.thread.ThreadState == ThreadState.WaitSleepJoin)
                    {
                        Thread.Sleep(200);
                    }
                    this.thread.Join();
                }
            }

            private void StartThread()
            {
                while ( this.bStartThread )
                {
                    Thread.Sleep(500);
                    Console.WriteLine("About to invoke");
                    // BeginInvoke - don't want to block waiting for UI thread to update,
                    // as it's going to be busy waiting for this work to be completed.
                    this.BeginInvoke( new AddRowDelegate( AddRow ) );
                    Console.WriteLine("invoked");
                }
            }

            // Code below for keeping thread alive.

    //        private void button1_Click(object sender, System.EventArgs e)
    //        {
    //            if (! this.bStartThread )
    //            {
    //                this.bStartThread = true;
    //                this.button1.Text = "Stop Thread";
    //                if ( !this.thread.IsAlive )
    //                {
    //                    this.thread.Start();
    //                }
    //            }
    //            else
    //            {
    //                this.bStartThread = false;
    //                this.button1.Text = "Start Thread";
    //            }
    //        }
    //
    //        private void StartThread()
    //        {
    //            while(true)
    //            {
    //                while ( this.bStartThread )
    //                {
    //                    this.Invoke( new AddRowDelegate( AddRow ) );
    //                    Thread.Sleep(500);
    //                }
    //            }
    //        }
        }


  • Deepak K

    The problem is in your StartThread method. Since it runs on a different thread, you're not allowed to access the Form's controls. You need to use Invoke to perform the changes you want to do on the original thread.

    Here are some articles on Invoke:
    http://www.theserverside.net/discussions/thread.tss thread_id=25063 (with code sample)
    http://weblogs.asp.net/justin_rogers/articles/126345.aspx (advanced)

  • Problem with threading in C#