Skip to main content
decreased code indentation, added backticks in one place
Source Link

Updated Answer: As @Vasyl pointed out Semaphore may be disposed before completion of tasks and will raise exception when Release()Release() method is called so before exiting the using block must wait for the completion of all created Tasks.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach(var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => {   try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } Task.WaitAll(tasks.ToArray()); } 
static void Main(string[] args)  {   int maxConcurrency = 5;   List<string> messages = Enumerable.Range(1, 15).Select(e => e.ToString()).ToList();   using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))   {   List<Task> tasks = new List<Task>();   foreach (var msg in messages)   {   concurrencySemaphore.Wait();   var t = Task.Factory.StartNew(() =>   {     try   {   Process(msg);   }   finally   {   concurrencySemaphore.Release();   }   });   tasks.Add(t);   }   // Task.WaitAll(tasks.ToArray());   }   Console.WriteLine("Exited using block");     Console.ReadKey();  }    private static void Process(string msg)  {   Thread.Sleep(2000);   Console.WriteLine(msg);    } } 

Updated Answer: As @Vasyl pointed out Semaphore may be disposed before completion of tasks and will raise exception when Release() method is called so before exiting the using block must wait for the completion of all created Tasks.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach(var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => {   try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } Task.WaitAll(tasks.ToArray()); } 
static void Main(string[] args)  {   int maxConcurrency = 5;   List<string> messages = Enumerable.Range(1, 15).Select(e => e.ToString()).ToList();   using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))   {   List<Task> tasks = new List<Task>();   foreach (var msg in messages)   {   concurrencySemaphore.Wait();   var t = Task.Factory.StartNew(() =>   {     try   {   Process(msg);   }   finally   {   concurrencySemaphore.Release();   }   });   tasks.Add(t);   }   // Task.WaitAll(tasks.ToArray());   }   Console.WriteLine("Exited using block");     Console.ReadKey();  }    private static void Process(string msg)  {   Thread.Sleep(2000);   Console.WriteLine(msg);    } } 

Updated Answer: As @Vasyl pointed out Semaphore may be disposed before completion of tasks and will raise exception when Release() method is called so before exiting the using block must wait for the completion of all created Tasks.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach(var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => { try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } Task.WaitAll(tasks.ToArray()); } 
static void Main(string[] args) { int maxConcurrency = 5; List<string> messages = Enumerable.Range(1, 15).Select(e => e.ToString()).ToList(); using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach (var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => { try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } // Task.WaitAll(tasks.ToArray()); } Console.WriteLine("Exited using block"); Console.ReadKey(); } private static void Process(string msg) { Thread.Sleep(2000); Console.WriteLine(msg); } 
added code example where semaphore will be disposed without task.waitall
Source Link
ClearLogic
  • 3.8k
  • 1
  • 27
  • 33

Answer to Comments for those who want to see how semaphore can be disposed without Task.WaitAll Run below code in console app and this exception will be raised.

System.ObjectDisposedException: 'The semaphore has been disposed.'

static void Main(string[] args) { int maxConcurrency = 5; List<string> messages = Enumerable.Range(1, 15).Select(e => e.ToString()).ToList(); using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach (var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => { try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } // Task.WaitAll(tasks.ToArray()); } Console.WriteLine("Exited using block"); Console.ReadKey(); } private static void Process(string msg) { Thread.Sleep(2000); Console.WriteLine(msg); } } 

Answer to Comments for those who want to see how semaphore can be disposed without Task.WaitAll Run below code in console app and this exception will be raised.

System.ObjectDisposedException: 'The semaphore has been disposed.'

static void Main(string[] args) { int maxConcurrency = 5; List<string> messages = Enumerable.Range(1, 15).Select(e => e.ToString()).ToList(); using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach (var msg in messages) { concurrencySemaphore.Wait(); var t = Task.Factory.StartNew(() => { try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } // Task.WaitAll(tasks.ToArray()); } Console.WriteLine("Exited using block"); Console.ReadKey(); } private static void Process(string msg) { Thread.Sleep(2000); Console.WriteLine(msg); } } 
fixed a bug in the code
Source Link
ClearLogic
  • 3.8k
  • 1
  • 27
  • 33

SemaphoreSlim is a very good solution in this case and I higly recommend OP to try this, but @Manoj's answer has flaw as mentioned in comments.semaphore should be waited before spawning the task like this.

Updated Answer: As @Vasyl pointed out Semaphore may be disposed before completion of tasks and will raise exception when Release() method is called so before exiting the using block must wait for the completion of all created Tasks.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach(var msg in messages) { concurrencySemaphore.Wait();       var t = Task.Factory.StartNew(() => {   try { Process(msg); } finally { concurrencySemaphore.Release(); } }); } } 

semaphore can be released in the continuation like this

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) {  foreach(var msg in messages)   {  concurrencySemaphoretasks.WaitAdd(t); Task.Factory.StartNew(() =>   { }   Process(msg);    })Task.ContinueWithWaitAll( concurrencySemaphoretasks.ReleaseToArray() ); } } 

SemaphoreSlim is a very good solution in this case and I higly recommend OP to try this, but @Manoj's answer has flaw as mentioned in comments.semaphore should be waited before spawning the task like this.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { foreach(var msg in messages) { concurrencySemaphore.Wait();     Task.Factory.StartNew(() => {   try { Process(msg); } finally { concurrencySemaphore.Release(); } }); } } 

semaphore can be released in the continuation like this

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) {  foreach(var msg in messages)   {  concurrencySemaphore.Wait(); Task.Factory.StartNew(() =>   {    Process(msg);    }).ContinueWith( concurrencySemaphore.Release() ); } } 

SemaphoreSlim is a very good solution in this case and I higly recommend OP to try this, but @Manoj's answer has flaw as mentioned in comments.semaphore should be waited before spawning the task like this.

Updated Answer: As @Vasyl pointed out Semaphore may be disposed before completion of tasks and will raise exception when Release() method is called so before exiting the using block must wait for the completion of all created Tasks.

int maxConcurrency=10; var messages = new List<string>(); using(SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach(var msg in messages) { concurrencySemaphore.Wait();    var t = Task.Factory.StartNew(() => { try { Process(msg); } finally { concurrencySemaphore.Release(); } }); tasks.Add(t); } Task.WaitAll(tasks.ToArray()); } 
added 43 characters in body
Source Link
ClearLogic
  • 3.8k
  • 1
  • 27
  • 33
Loading
Source Link
ClearLogic
  • 3.8k
  • 1
  • 27
  • 33
Loading