Heey Guy's,

I'm having trouble understanding the Threading within an application.
I will try to explain the program:

2 forms
1 parent (Server)
1 child (Client)

both screens run on local computer (no network is needed)

The server generates a random number once I've pressed a button.
The number must be given to the Client
Witch will show the received value from the server within a label object.

So far I have tried the following:

Situation 1: (Not the first choice)

3 forms
1 parent (Server)
1 child (Client)
1 control (Control)

1 Extra screen from where I start the server and client, and an extra Start button.
This screen holds the Server object ant Client object, so i can call public methods (get randomnumber from server, SetRandomNumber on client)

here a code sample:

Controller (holding server + client object + start button)
Hereby the code from the

public partial class Control : Form
    {
        private Thread oThreadServer;
        private Thread oThreadClient;
        private Thread oThreadWorker;
        private BingoServer oFormServer = new Server();
        private BingoClient oFormClient = new Client();

        public Control()
        {
            InitializeComponent();
        }

        private void btn_server_Click(object sender, EventArgs e)
        {
            oThreadServer = new Thread(new ThreadStart(this.m_P_NewServer));
            oThreadServer.Start();
        }

        private void btn_client_Click(object sender, EventArgs e)
        {
            oThreadClient = new Thread(new ThreadStart(this.m_P_NewClient));
            oThreadClient.Start();
        }

        private void btn_start_Click(object sender, EventArgs e)
        {
            oThreadWorker = new Thread(new ThreadStart(this.m_P_StartGame));
            oThreadWorker.Start();
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            oThreadServer.Abort();
            oThreadClient.Abort();
            oThreadWorker.Abort();
            Application.Exit();
        }

        private void m_P_NewServer()
        {
            oFormServer.ShowDialog();
        }

        private void m_P_NewClient()
        {
            oFormClient.ShowDialog();
        }

        private void m_P_StartGame()
        {
            while (true) // todo -> only while in_game
            {
               oFormClient.mSetNewRandom(oFormServer.mGetRandomNumber());
            }
        }
        
    }

here is the code for the

public partial class Client : Form
    {        
        public Client()
        {
            InitializeComponent();
        }

        private void btn_close_Click(object sender, EventArgs e)
        {
            Application.ExitThread();
        }

        public void mSetNewRandom(int p_NewRandom)
        {
            this.lbl_number.Text = p_NewRandom.ToString();
        }
    }

as you can see I've got a thread for Client, a thread for the server, and a thread that gets the value from the server and gives it to the client.

the problem is when i want to give the client the value, the whole program crashes. Error is saying that Thread (oThreadWorker) cannot change a value within oThreadClient.
Getting a value from within oThreadServer using oThreadWorker is no problem.

Situation 2: (the first choice)

2 Screens:
1 Server
1 Client

this situation starts the client from within the server.
Same as situation 1 => client has public funcion -> but crashes deu to Tread problem.

The Question

Am I thinking in the wrong direction, trying to solve my problem, or am I missing something.

Dani AI

Generated

Quick diagnosis and practical fixes.

The crash is the classic WinForms cross-thread problem: Windows controls have thread affinity and must be accessed only from the thread that created them. ’s pointer to using Invoke is correct, but the code needs two architectural fixes at once: (a) make sure each Form is created and shown on the thread that will own its message loop, or keep all UI on a single thread, and (b) marshal any background-thread updates back to that UI thread rather than writing control properties directly.

Two safe approaches that work reliably:

  • Single-UI-thread (simpler): create and show both forms on the main/UI thread, run the random-number work on a background Task/Thread, and marshal label updates to the UI with BeginInvoke/InvokeAsync or use IProgress<T>/SynchronizationContext. This avoids multiple message loops and is easiest to maintain.

  • Separate-UI-thread (when required): create the form inside the worker thread and start a message loop with Application.Run(form). That thread becomes the form’s owner; other threads must then call that form’s Invoke/BeginInvoke to update controls.

Example patterns:

// safe setter inside the client form
public void SetRandomSafe(int value)
{
    if (this.InvokeRequired)
    {
        this.BeginInvoke(new Action<int>(SetRandomSafe), value);
        return;
    }
    lblNumber.Text = value.ToString();
}
// start a form on its own UI thread
var t = new Thread(() => Application.Run(new Client()));
t.SetApartmentState(ApartmentState.STA);
t.Start();

Troubleshooting notes: avoid tight while(true) loops for polling (use events, timers or blocking queues), do not call Thread.Abort or rely on Application.ExitThread for cleanup — prefer cooperative cancellation (CancellationToken) and Form.Close. Also beware that InvokeRequired can be misleading if the control’s handle isn’t created; check lifetime/IsHandleCreated and ensure the form is shown before trying to invoke. Microsoft’s WinForms threading guidance and the notes about running a form on its own thread are helpful references: How to handle cross-thread operations with controls (learn.microsoft.com) and Display each Windows Form on its own thread (Application.Run). (learn.microsoft.com)

Most likely you'll need to invoke on the client form (Invoke)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.