title: Is this C# Parallel.ForEach "localFinally" method thread safe?
body: <p>Due to the benefits stated by MicroSoft, I'm implementing a large series of SQL SELECT statements (multiple-thousands of them) using <code>Parallel.ForEach</code> <em>(BTW: I can't find it now, but I'm pretty sure I read somewhere that Parallel.ForEach won't return control until all iterations have been executed. Is this true?)</em></p>
  
  <p>I began with <a href="https://stackoverflow.com/questions/16090460/parallel-foreach-sql-querying-sometimes-results-in-connection">Parallel.Foreach SQL querying sometimes results in Connection</a>. I don't want to use the accepted answer because it abandoned <code>Parallel.ForEach</code> and used instead just <code>Task.Run</code> (or <code>Task Factory.StartNew</code> for .Net 4.0). At the same time, the O.P. used "lock" to sync updates to a list of <code>DataTable</code> which I understand may lessen the efficiency of <code>Parallel.ForEach</code>.</p>
  
  <p>So, using the article <a href="https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables" rel="nofollow noreferrer">How to: Write a Parallel.ForEach Loop with Thread-Local Variables</a>, I wrote the strawman code below. The goal is to accumulate the <code>threadLocalDataTable</code> (one per select statement) to the <code>dataTableList</code> that is returned once all queries are done. It works, but I wonder if the <code>localFinally</code> method is really thread safe (see the line of code with the comment <code>//&lt;-- the localFinally method in question</code>. <em>Note: the SqlOperation class implements a connection string, output datatable name, and select query string</em></p>
  
  <pre><code>public static IList&lt;DataTable&gt; GetAllData(IEnumerable&lt;SqlOperation&gt; sqlList)
  {
      IList&lt;DataTable&gt; dataTableList = new List&lt;DataTable&gt;();
      dataTableList.Clear();
  
      try
      {
  
          Parallel.ForEach&lt;SqlOperation, DataTable&gt;(sqlList, () =&gt; null, (s, loop, threadLocalDataTable) =&gt;
          {
  
              DataTable dataTable = null;
  
              using (SqlCommand sqlCommand = new SqlCommand())
              {
                  using (SqlConnection sqlConnection = new SqlConnection(s.ConnectionString))
                  {
                      sqlConnection.Open();
                      sqlCommand.CommandType = CommandType.Text;
                      sqlCommand.Connection = sqlConnection;
                      sqlCommand.CommandText = s.SelectQuery;
                      SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
  
                      dataTable = new DataTable
                      {
                          TableName = s.DataTableName
                      };
  
                      dataTable.Clear();
                      dataTable.Rows.Clear();
                      dataTable.Columns.Clear();
  
                      sqlDataAdapter.Fill(dataTable);
                      sqlDataAdapter.Dispose();
                      sqlConnection.Close();
                  }
              }
  
              return dataTable;
  
  
          }, (threadLocalDataTable) =&gt; dataTableList.Add(threadLocalDataTable) //&lt;-- the localFinally method in question
          );
      }
      catch (Exception ex)
      {
          Console.WriteLine(ex.ToString(), "GetAllData error");
      }
  
      return dataTableList;
  }
  </code></pre>