簡體   English   中英

為什么lock關鍵字不適用於此多線程實現?

[英]why is the lock keyword not working with this multi-threading implementation?

我正在嘗試將Parallel.ForEach()構造用於多線程,並且遇到一些問題。 具體來說,某些數據需要進行不同的評估,這似乎在ForEach()構造中造成了一些問題,在該構造中,某些屬性已使用來自不同線程的值進行設置。 我以為我可以用鎖簡單地包裝該特定代碼,但是問題仍然存在。 您可以通過查看以下代碼來確定問題的根源嗎:

https://dotnetfiddle.net/IDUGbP

這是內聯代碼:

using SecurityApi.Core.Models;
using SecurityApi.Core.Repositories;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using SecurityApi.EntityFramework;
using System.DirectoryServices;

namespace SecurityApi.Repositories
{
    [Export(typeof(IADUserRepository))]
    public class ADUserRepository : IADUserRepository
    {
        private Object etlLock = new Object();

        public async Task<List<Core.Models.ADUser>> GetADUsersFromAD(string domainName)
        {
            var domainId = await new DomainRepository().GetDomainId(domainName);
            var adUsers = new ConcurrentBag<Core.Models.ADUser>();
            var adGroups = new ConcurrentBag<Core.Models.ADGroup>();

            return await Task.Run(() =>
            {
                using (var context = new PrincipalContext(ContextType.Domain, domainName))
                {
                    // init vars
                    var up = new UserPrincipal(context);
                    var ps = new PrincipalSearcher(up);
                    Core.Models.ADUser adUser;

                    Parallel.ForEach(
                        ps.FindAll().ToList(), 
                        new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
                        result =>
                    {
                        if (!result.DistinguishedName.Contains("OU=Users")) return;

                        //set ad user properties
                        var userPrincipal = result as UserPrincipal;
                        adUser.Name = userPrincipal.Name;
                        adUser.FirstName = userPrincipal.GivenName;
                        adUser.LastName = userPrincipal.Surname;

                        lock (etlLock)
                        {
                            //get a directory entry representation for accessing special properties
                            var directoryEntry = result.GetUnderlyingObject() as DirectoryEntry;

                            //user principal name
                            adUser.UserPrincipalName = directoryEntry.Properties["UserPrincipalName"].Value?.ToString();

                            //employee id
                            adUser.EmployeeId = directoryEntry.Properties["EmployeeId"].Value?.ToString();
                        }

                        #endregion

                        adUsers.Add(adUser);
                    });
                }

                return adUsersList;
            });
        }
    }
}

問題是臨時adUser變量是在Parallel.ForEach塊的外部范圍中定義的,這導致不同的線程對其進行修改。 相反,請考慮將定義移到foreach主體中,在該主體中實際設置變量。 這樣,每個線程將獲得其自己的變量。 當然,這里的問題是Parallel.Foreach是否對重復的引用進行操作,但我認為沒有。

在這里,我將如何修改您的代碼: https : //dotnetfiddle.net/gFb5z6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM