Threading and Incrementing

So I think this might be a fundamental flaw in my approach to threading and incrementing a global counter, but here is my problem. I have a collection of file names from a DB that I iterate through, and for each file name I search it within a top level folder. Each iteration I thread the search and increment a counter when it completes so I can determine when it finishes. The problem is the counter never ever ever gets as high as the total file count, it comes very close sometimes, but never reaches what I would expect.

public class FindRogeRecords
{
    private delegate void FindFileCaller(string folder, int uploadedID, string filename);
    private Dictionary<int, string> _files;
    private List<int> _uploadedIDs;
    private int _filesProcessedCounter;
    private bool _completed;

    public void Run()
    {
        _files = GetFilesFromDB(); //returns a dictionary of id's and filenames
        FindRogueRecords();
    }

    private void FindRogueRecords()
    {
            _uploadedIDs = new List<int>();

        foreach (KeyValuePair<int, string> pair in _files)
        {
            var caller = new FindFileCaller(FindFile);
            var result = caller.BeginInvoke(txtSource.Text, pair.Key, pair.Value, new AsyncCallback(FindFile_Completed), null);
        }
    }

    private void FindFile(string documentsFolder, int uploadedID, string filename)
    {
        var docFolders = AppSettings.DocumentFolders;

        foreach (string folder in docFolders)
        {
            string path = Path.Combine(documentsFolder, folder);
            var directory = new DirectoryInfo(path);
            var files = directory.GetFiles(filename, SearchOption.AllDirectories);

            if (files != null && files.Length > 0) return;
        }

        lock (_uploadedIDs) _uploadedIDs.Add(uploadedID);
    }

    private void FindFile_Completed(System.IAsyncResult ar)
    {
        var result = (AsyncResult)ar;
        var caller = (FindFileCaller)result.AsyncDelegate;

        _filesProcessedCounter++;
        _completed = (_files.Count == _filesProcessedCounter); //this never evaluates to true
    }
}

Answers


You are accessing _filesProcessedCounter variable from multiple threads without any synchronization (even simple lock()) so this caused Race Condition in your code.

To increment an integer variable you can use Interlocked.Increment() which is thread-safe but considering that following line of code requires synchronization as well:

_completed = (_files.Count == _filesProcessedCounter); 

I would suggest using lock object to cover both lines and keep code much clear:

// Add this field to a class fields list
private static readonly object counterLock = new object();

// wrap access to shared variables by lock as shown below
lock (counterLock)
{
  _filesProcessedCounter++;
  _completed = (_files.Count == _filesProcessedCounter);   
}

Need Your Help

Do the amount of methods in a python class affect performance?

python performance class methods

I am creating a Python class to represent a Geographic Position. Its main goal is to store latitude, longitude, elevation, so it is going to be used much like a C# "struct", a value type that is su...

Focus a editable grid's row within the form

extjs extjs4 extjs4.1 extjs-mvc

I have a editable grid (Ext.grid.plugin.RowEditing)

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.