线程和增量

Chr*_*ris 1 c# multithreading

所以我认为这可能是我在线程和递增全局计数器方法中的一个根本缺陷,但这是我的问题.我有一个来自我迭代的数据库的文件名集合,对于每个文件名,我在顶级文件夹中搜索它.每次迭代我都会搜索并在计数器完成时递增计数器,这样我就可以确定它何时完成.问题是计数器永远不会像文件总数一样高,有时会非常接近,但永远不会达到我的预期.

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
    }
}
Run Code Online (Sandbox Code Playgroud)

sll*_*sll 5

您正在_filesProcessedCounter从多个线程访问变量而没有任何同步(甚至是简单的lock()),因此这会在您的代码中导致Race Condition.

要增加整数变量,可以使用Interlocked.Increment(),这是线程安全的,但考虑到以下代码行也需要同步:

_completed = (_files.Count == _filesProcessedCounter); 
Run Code Online (Sandbox Code Playgroud)

我建议使用锁定对象来覆盖两行并保持代码清晰:

// 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);   
}
Run Code Online (Sandbox Code Playgroud)