0

I'm a bit new to using Semaphores, and I'm a bit confused by this. All I'm doing is grabbing the html code from a page, and writing it to a file, over and over. When I use it in a foreach, it works perfectly. When I change it over to a for loop, I get a the file is used by another process exception, and it references the file that is after the max count. What is the difference between these two? They should be processing the same files.

Works perfectly:

    private async Task GetFiles()
    {
        string strDir = ConfigurationManager.AppSettings["location"];
        var maxThreads = 4;
        var allTasks = new List<Task>();
        SemaphoreSlim throttler = new SemaphoreSlim(initialCount: maxThreads);

        foreach(FileToProcess ftpFile in lstFiles)
        {
                await throttler.WaitAsync();
                allTasks.Add(
                    Task.Run(async () =>
                    {
                        try
                        {
                            await GetHtmlFromUrlAsync(ftpFile, strDir);
                        }
                        finally
                        {
                            throttler.Release();
                        }
                    }));
        }
        await Task.WhenAll(allTasks);
    }

Gets an error after on the 5th item in the list (max thread + 1). If I adjusted the max thread count, the error would change as well:

    private async Task GetFiles()
    {
        string strDir = ConfigurationManager.AppSettings["location"];
        var maxThreads = 4;
        var allTasks = new List<Task>();
        SemaphoreSlim throttler = new SemaphoreSlim(initialCount: maxThreads);

        for (int x = 0; x < lstFiles.Count; x++)
        {
                await throttler.WaitAsync();
                allTasks.Add(
                    Task.Run(async () =>
                    {
                        try
                        {
                            await GetHtmlFromUrlAsync(lstFiles[x], strDir);
                        }
                        finally
                        {
                            throttler.Release();
                        }
                    }));
        }
        await Task.WhenAll(allTasks);
    }
Vandel212
  • 1,074
  • 1
  • 13
  • 28
  • 3
    I suspect that your issue has nothing to do with the Semaphore. In the lambda expression that you use for the async task, you are capturing the for loop counter. When you capture a variable, you are grabbing a reference to the variable itself, not the value of the variable at the moment when you capture it. Try to add a line of code as the first instruction inside the for loop body, where you create a copy of the x variable. Something like: `int counter = x;`. The use `counter` in the lambda expression, instead of referencing the `x` variable. – Enrico Massone Aug 11 '21 at 21:38
  • See this reply on stackoverflow: https://stackoverflow.com/a/271447/4331637 – Enrico Massone Aug 11 '21 at 21:53
  • 1
    That was the trick Enrico, thank you! – Vandel212 Aug 12 '21 at 13:57

0 Answers0