C# 我可以为这个场景设计任何无锁解决方案吗

C# 我可以为这个场景设计任何无锁解决方案吗,c#,.net-4.0,locking,task-parallel-library,async-await,C#,.net 4.0,Locking,Task Parallel Library,Async Await,我有一个简单的Employee类,如下所示 public class Employee { public int ID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } } 然后我有一个ProcessEmployees类,它在名为ProcessThisEmployee的方法中对这些员工进行并发处理。在这个

我有一个简单的Employee类,如下所示

public class Employee
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
    }
然后我有一个ProcessEmployees类,它在名为ProcessThisEmployee的方法中对这些员工进行并发处理。在这个方法中,我必须调用第三方库方法。到目前为止,一切都很简单。问题是,当用户选择取消正在进行的操作时,我需要对任何尚未完成处理的第三方库类实例进行清理。注意,我对ThirdPartyLibrary类没有任何控制权,它也没有任何取消现有任务的机制。它确实提供了一个干净的方法,我可以在调用SomeAPI尚未完成的任何实例上调用它。因此,我维护了所有实例的本地列表。当用户选择取消操作时,我调用我的类的CleaupIfUserCancelOperation方法来清除我本地列表中这个第三方库实例的方法。下面是我的代码

class ProcessEmployees
{
    private List<Employee> _Employees;
    List<ThirdPartyLibrary> libraries = new List<ThirdPartyLibrary>();
    private object sync = new object();
    public  ProcessEmployees()
    {
        _Employees = new List<Employee>() 
        {
            new Employee() { ID = 1, FirstName = "John", LastName = "Doe" },
            new Employee() { ID = 2, FirstName = "Peter", LastName = "Saul" },
            new Employee() { ID = 3, FirstName = "Mike", LastName = "Sue" },
            new Employee() { ID = 4, FirstName = "Catherina", LastName = "Desoza" },
            new Employee() { ID = 5, FirstName = "Paul", LastName = "Smith" }
        };
    }

    public void StartProcessing()
    {

        Task[] tasks = this._Employees.AsParallel().Select(x => this.ProcessThisEmployee(x)).ToArray();
        Task.WaitAll(tasks);
        // other stuff
    }

    private async Task ProcessThisEmployee(Employee x)
    {
        ThirdPartyLibrary library = new ThirdPartyLibrary();
        lock (sync)
        {
            libraries.Add(library);
        }
        await Task.Factory.StartNew(() => library.SomeAPI(x) );

        lock (sync)
        {
            libraries.Remove(library);
        }
    }

    private void CleaupIfUserCancelOperation()
    {
        foreach (ThirdPartyLibrary library in libraries)
            library.Clean();
    }
}
类处理员工
{
私人名单(员工),;
列表库=新列表();
私有对象同步=新对象();
公职人员()
{
_雇员=新名单()
{
新员工(){ID=1,FirstName=“John”,LastName=“Doe”},
新员工(){ID=2,FirstName=“Peter”,LastName=“Saul”},
新员工(){ID=3,FirstName=“Mike”,LastName=“Sue”},
新员工(){ID=4,FirstName=“Catherina”,LastName=“Desoza”},
新员工(){ID=5,FirstName=“Paul”,LastName=“Smith”}
};
}
公共无效启动处理()
{
Task[]tasks=this.\u Employees.AsParallel().选择(x=>this.ProcessThisEmployee(x)).ToArray();
Task.WaitAll(任务);
//其他东西
}
私有异步任务流程ThisEmployee(员工x)
{
第三方图书馆=新的第三方图书馆();
锁定(同步)
{
图书馆。添加(图书馆);
}
wait Task.Factory.StartNew(()=>library.SomeAPI(x));
锁定(同步)
{
图书馆。移除(图书馆);
}
}
私有void CleaupIfUserCancelOperation()
{
foreach(图书馆中的第三方图书馆)
library.Clean();
}
}

我必须在这里锁定库实例两次,这当然是一个性能上的损失。在这种情况下可以使用任何轻量级(无锁)机制吗?我对并发集合了解不多,不知道它们在这种情况下是否有用?

这两个锁调用对性能的影响很可能比您正在进行的其他调用小得多。假设有,您可以使用
ConcurrentDictionary
添加和删除实例(无论如何,您不应该使用列表,因为现在并发库的数量有二次性能开销)


最好是让每个异步方法取消它自己并清理它自己的东西。向他们传递一个
CancellationToken
。使用
Register
注册清除库的回调。这里确实不需要全局状态/集合。

我根据您的一些建议提出了另一种方法,但我不确定这是否是最佳方法。我已将单独的问题发布在