*
Previous C# Threading QA-1-10 C# Threading QA-21-30 Next

Dot net Framework (C#) Threading Question Answers - 11-20

11. Explain synchronization primitives for controlling the interactions of threads and avoiding race conditions.

Synchronization primitives can be roughly divided into three categories:

  • Locking: lock, Monitor, Mutex, etc.
  • Signaling: Join, WaitHandles, etc.
  • Interlocked operations: atomic operations using Interlocked class (e.g., Add, Increment, Exchange, CompareExchange).

12. Example for joining the ThreadPool via asynchronous delegates

// Enter the thread pool via asynchronous delegates
static void Main()
{
  Func<string, int> method = DoWork;
  IAsyncResult cookie = method.BeginInvoke("From Asynchronous delegates", null, null);

  // ...Do other work here in parallel

  int result = method.EndInvoke(cookie);
  Console.WriteLine("String length: " + result);
}

static int DoWork(string s) 
{ 
  return s.Length; 
}

// Output
// String length: 27

13. Example for joining the ThreadPool via BackgroundWorker

using System.ComponentModel;
using System.Threading;

class BackgroundWorkerEx
{
  static BackgroundWorker _bw = new BackgroundWorker();
  static void Main()
  {
    int worker = 0, io = 0;
    ThreadPool.GetAvailableThreads(out worker, out io);
    Console.WriteLine("Total Threads in the Pool: -> " + worker + ", IO thread-> " + io);

    _bw.DoWork += bw_DoWork;
    _bw.RunWorkerAsync("Message to worker");
    Console.ReadLine();
  }

  static void bw_DoWork(object sender, DoWorkEventArgs e)
  {
    int worker = 0, io = 0;
    ThreadPool.GetAvailableThreads(out worker, out io);
    Console.WriteLine("Remaining Threads: -> " + worker + ", IO thread-> " + io);
    Console.WriteLine(e.Argument); // "Message to worker"
  }
}

// Output
// Total Threads in the Pool: -> 3200, IO thread-> 3200
// Remaining Threads: -> 3198, IO thread-> 3200
// Message to worker

14. Example for joining the ThreadPool via Task Parallel Library (TPL)

using System.Threading;
using System.Threading.Tasks;

class ProgramThreadPool
{
  static void Main()
  {
    int worker = 0, io = 0;
    ThreadPool.GetAvailableThreads(out worker, out io);
    Console.WriteLine("Total Threads in the Pool: -> " + worker + ", IO thread-> " + io);
    Task.Factory.StartNew(DoWork);
  }

  static void DoWork()
  {
    int worker = 0, io = 0;
    ThreadPool.GetAvailableThreads(out worker, out io);
    Console.WriteLine("Remaining Threads: -> " + worker + ", IO thread-> " + io);
    Console.WriteLine("Hello from the thread pool!");
  }
}

// Output
// Total Threads in the Pool: -> 3200, IO thread-> 3200
// Remaining Threads: -> 3199, IO thread-> 3200
// Hello from the thread pool!

15. How to fix race conditions

  • Use locking mechanisms: C# provides mechanisms like lock statements, Mutex, Semaphore, and Monitor to synchronize access to shared resources. These mechanisms ensure that only one thread can access the critical section of code at a time, preventing race conditions.
  • Use atomic operations: Interlocked The System.Threading.Interlocked class provides atomic operations that can be used to perform operations like incrementing, decrementing, or exchanging values without the risk of race conditions.
  • Use concurrent collections: The System.Collections.Concurrent namespace provides thread-safe collection classes that handle synchronization internally, making it easier to work with shared data in a multi-threaded environment.

16. How to get the current Thread?

Use Thread.CurrentThread property.

17. How to pass data to a thread?

To pass arguments to a thread’s target method is to execute a lambda expression that calls the method with the desired arguments:

static void Main()
{
  Thread t = new Thread(() => Print("Hello from t!"));
  t.Start();
}

static void Print(string message)
{
  Console.WriteLine(message);
}

18. How to prevent deadlock?

  • Consistent locking order: Always acquire locks in the same order to avoid circular dependencies.
  • Timeout mechanism (e.g., Monitor.TryEnter): Implement a timeout when acquiring a lock, so a thread doesn't wait indefinitely.
  • Resource hierarchy: Define a hierarchy of resources and acquire locks according to that hierarchy.
  • Use higher-level synchronization (e.g., ReaderWriterLockSlim):Employ constructs like Monitor.TryEnter with a timeout or use ReaderWriterLockSlim which provides more sophisticated synchronization options.

19. Does a blocked thread consume CPU resources?

No, a blocked thread does not consume CPU resources.

20. Important Thread Methods

  • Start: Begins execution.
  • Sleep: Pauses execution for a time.
  • Suspend: Pauses a thread (deprecated).
  • Abort: Stops a thread (deprecated).
  • Resume: Restarts a suspended thread (deprecated).
  • Join: Waits for a thread to finish.
Back to Index
Previous C# Threading QA-1-10 C# Threading QA-21-30 Next
*
*