title: C# Thread.Join() blocks the main thread
body: <p>I have 3 threads running: the main thread, the readData thread and the acquisition thread. From a form, when the play button is clicked, it starts the device acquisition and the readData threads. When the Stop button is pressed I wanna stop both threads. However, the acqusitionThread.Join() blocks the execution. What am I doing wrong?</p>
  
  <p>Main Form  </p>
  
  <pre><code> private void btnPlay_Click(object sender, EventArgs e)
          {
            daqObj.Start();
          }
  
          private void btnStop_Click(object sender, EventArgs e)
          {
            daqObj.Stop();
          }
  </code></pre>
  
  <p>Data acqusition class to read the data from the device</p>
  
  <pre><code>     public void Start()
              {
                  _isRunning = true;
  
              acquisitionDevice.StartAcquisition(); //starts thread for acquisition
  
                  //start data acquisition thread
                  _readDataThread = new Thread(readData);
                  _readThread.Name = "Read data Thread";
                  _redThread.Priority = ThreadPriority.AboveNormal;
                  _readThread.Start();
              }
  
         public void ReadData()
          {
  
              try
              {
                  // write data to file
                  while (_isRunning)
                  {
                      //Reads data (dequeues from buffer)
                      float[] data = acquisitionDevice.ReadData(numValuesAtOnce);
  
                      //Do other stuff with data (eg: save to file)
                  }
                  }
                  catch (Exception ex)
                  {
                      Console.WriteLine("\t{0}", ex.Message);
                  }
      }
  
  
              public void Stop()
              {
                  _isRunning = false;
  
                      if ((_writeToFileThread != null) &amp;&amp; _writeToFileThread.IsAlive)
                          _writeToFileThread.Join(); //stop readData thread
  
                      acquisitionDevice.StopAcquisition(); //stops acquisition thread
  
                       Console.WriteLine("acquisiton thread stopped); //THIS IS NEVER EXECUTED
  
              }
  </code></pre>
  
  <p>Device acqusition class:</p>
  
  <pre><code> public void StartAcquisition(Dictionary&lt;string, DeviceConfiguration&gt; deviceSerials)
          {
              //ensure that data acquisition is not already running
              if (_isRunning || (_acquisitionThread != null &amp;&amp; _acquisitionThread.IsAlive))
                  throw new InvalidOperationException("Data acquisition is already running!");
  
              _isRunning = true;
  
              //initialize buffer
              _buffer = new WindowedBuffer&lt;float&gt;(BufferSizeSeconds * sampleRate * totalChannels);
  
              //start data acquisition thread
              _acquisitionThread = new Thread(DoAcquisition);
              _acquisitionThread.Name = "DataAcquisition Thread";
              _acquisitionThread.Priority = ThreadPriority.Highest;
              _acquisitionThread.Start(deviceSerials);
          }
  
   public void StopAcquisition()
          {
              //tell the data acquisition thread to stop
              _isRunning = false;
  
              //wait until the thread has stopped data acquisition
              if (_acquisitionThread != null)
                  _acquisitionThread.Join(); //THIS BLOCKS
  
              Console.WriteLine("ended"); //THIS IS NEVER EXECUTED
          }
  </code></pre>
  
  <p><strong>EDIT</strong>
  Instead of a separate thread for reading the data, I do it inside a token cancellation. I use a separate thread for data acquisition form the device (this is needed to continuously get data) and then I read it and write it to a file with a token cancellation.This is the code that works:</p>
  
  <pre><code>public void StartAcquisition()
              {
                  // Initialize token
                  _cancellationTokenSourceObj = new CancellationTokenSource();
                  var token = _cancellationTokenSourceObj.Token;
  
                      Task.Factory.StartNew(() =&gt;
                 {
  
                     // Start acquisition
                     try
                     {
                         // Write device configuration parameters to .txt file
                         System.IO.StreamWriter file = new System.IO.StreamWriter(deviceConfFilePath);
                         file.WriteLine(gUSBampObj.GetDeviceConfigurationString());
                         file.Close();
  
                         // create file stream
                         using (_fileStream = new FileStream(daqFilePath, FileMode.Create))
                         {
                             using (BinaryWriter writer = new BinaryWriter(_fileStream))
                             {
                                 // start acquisition thread
                                 deviceAcquisition.StartAcquisition();
  
                                 // write data to file
                                 while (!token.IsCancellationRequested)
                                 {
                                     float[] data = deviceAcquisition.ReadData(numValuesAtOnce);
  
                                     // write data to file
                                     for (int i = 0; i &lt; data.Length; i++)
                                         writer.Write(data[i]);
                                 }
                             }
                         }
                     }
                     catch (Exception ex)
                     {
                         Console.WriteLine("\t{0}", ex.Message);
                     }
  
                 }, token)
             .ContinueWith(t =&gt;
             {
                 //This will run after stopping, close files and devices here
  
                 // stop data acquisition
                 deviceAcquisition.StopAcquisition();
  
             });
  
  
                  }
              }
  
  public void StopAcquisition()
  {
      _cancellationTokenSourceObj.Cancel();
  }
  </code></pre>