C# 不支持sta线程上多个句柄的waitall

C# 不支持sta线程上多个句柄的waitall,c#,multithreading,exception,C#,Multithreading,Exception,嗨,当我运行我的应用程序时,我有这个例外。 我在.net 3.5上工作,因此无法使用Task 不支持sta线程上多个句柄的waitall 代码如下:- private void ThreadPopFunction(ContactList SelectedContactList, List<User> AllSelectedUsers) { int NodeCount = 0; AllSelectedUsers.EachParallel(user =&

嗨,当我运行我的应用程序时,我有这个例外。 我在.net 3.5上工作,因此无法使用
Task

不支持sta线程上多个句柄的waitall

代码如下:-

private void ThreadPopFunction(ContactList SelectedContactList, List<User> AllSelectedUsers)
{
        int NodeCount = 0;

        AllSelectedUsers.EachParallel(user =>
        {
            NodeCount++;
            if (user != null)
            {
                if (user.OCSEnable)
                {
                    string messageExciption = string.Empty;
                    if (!string.IsNullOrEmpty(user.SipURI))
                    {
                        //Lync.Lync.Lync lync = new Lync.Lync.Lync(AdObjects.Pools);
                        List<Pool> myPools = AdObjects.Pools;
                        if (new Lync.Lync.Lync(myPools).Populate(user, SelectedContactList, out messageExciption))
                        {
                        }
                    }
                }
            }
        });
}
private void threadpop函数(ContactList SelectedContactList,List all selecteduser)
{
int NodeCount=0;
所有SelectedUsers.EachParallel(用户=>
{
NodeCount++;
如果(用户!=null)
{
if(user.OCSEnable)
{
string messageExciption=string.Empty;
如果(!string.IsNullOrEmpty(user.SipURI))
{
//Lync.Lync.Lync Lync=新建Lync.Lync.Lync(ADObject.Pools);
List myPools=AdObjects.Pools;
if(新建Lync.Lync.Lync(myPools).Populate(用户,SelectedContactList,out messageexOption))
{
}
}
}
}
});
}
这是我用来处理多线程的扩展方法

public static void EachParallel<T>(this IEnumerable<T> list, Action<T> action)
{
    // enumerate the list so it can't change during execution
    // TODO: why is this happening?
    list = list.ToArray();
    var count = list.Count();

    if (count == 0)
    {
        return;
    }
    else if (count == 1)
    {
        // if there's only one element, just execute it
        action(list.First());
    }
    else
    {
        // Launch each method in it's own thread
        const int MaxHandles = 64;
        for (var offset = 0; offset <= count/MaxHandles; offset++)
        {
            // break up the list into 64-item chunks because of a limitiation in WaitHandle
            var chunk = list.Skip(offset*MaxHandles).Take(MaxHandles);

            // Initialize the reset events to keep track of completed threads
            var resetEvents = new ManualResetEvent[chunk.Count()];

            // spawn a thread for each item in the chunk
            int i = 0;
            foreach (var item in chunk)
            {
                resetEvents[i] = new ManualResetEvent(false);
                ThreadPool.QueueUserWorkItem(new WaitCallback((object data) =>
                {
                    int methodIndex =
                        (int) ((object[]) data)[0];

                    // Execute the method and pass in the enumerated item
                    action((T) ((object[]) data)[1]);

                    // Tell the calling thread that we're done
                    resetEvents[methodIndex].Set();
                }), new object[] {i, item});
                i++;
            }

            // Wait for all threads to execute
            WaitHandle.WaitAll(resetEvents);
        }
    }
}
publicstaticvoideachparallel(此IEnumerable列表,操作)
{
//枚举列表,使其在执行期间不会更改
//托多:为什么会这样?
list=list.ToArray();
var count=list.count();
如果(计数=0)
{
返回;
}
否则如果(计数=1)
{
//如果只有一个元素,就执行它
动作(list.First());
}
其他的
{
//在它自己的线程中启动每个方法
const int MaxHandles=64;
对于(var offset=0;offset
{
int方法索引=
(int)((对象[])数据)[0];
//执行该方法并传入枚举项
动作((T)((对象[])数据)[1]);
//告诉呼叫线程我们完成了
resetEvents[methodIndex].Set();
}),新对象[]{i,item});
i++;
}
//等待所有线程执行
WaitHandle.WaitAll(重置事件);
}
}
}

如果您能帮助我,我将感谢您的支持

好的,因为您使用的是.Net 3.5,您不能使用.Net 4.0引入的TPL

不管是不是STA线程,在您的情况下,有一种比
WaitAll
更简单/有效的方法。您只需拥有一个计数器和一个唯一的
WaitHandle
。下面是一些代码(目前无法测试,但应该可以):

//没有MaxHandle限制;)
对于(var offset=0;offset
{
int方法索引=
(int)((对象[])数据)[0];
//执行该方法并传入枚举项
动作((T)((对象[])数据)[1]);
//反原子递减
联锁减量(参考计数器);
//如果我们在0,则执行最后一个操作
if(联锁读取(参考计数器)==0)
{
resetEvent.Set();
}
}),新对象[]{i,item});
}
//等待单个WaitHandle
//仅在执行最后一个操作时设置
resetEvent.WaitOne();
}

另外,仅供参考,
ThreadPool.QueueUserWorkItem
不会在每次调用时生成线程(我之所以这么说是因为有一条注释“为区块中的每个项目生成线程”)。它使用一个线程池,因此它主要重用现有线程。

对于像我这样需要使用示例的人来说。 ken2k的解决方案很好,它可以工作,但有一些修正(他说他没有测试它)。以下是ken2k的工作示例(为我工作):

//没有MaxHandle限制;)
对于(var offset=0;offset
{
int方法索引=
(int)((对象[])数据)[0];
//执行该方法并传入枚举项
动作((T)((对象[])数据)[1]);
//反原子递减
联锁减量(参考计数器);
//如果我们在0,则执行最后一个操作
if(联锁读取(参考计数器)==0)
{
resetEvent.Set();
}
}),新对象[]{i,item});
}
//等待单个WaitHandle
//仅在执行最后一个操作时设置
resetEvent.WaitOne();
}

事实上,在.NET3.5中有一种使用TPL的方法(至少是很好的一部分)。有一个为Rx项目完成的后端口

你可以在这里找到它:


也许这会有帮助。

嗯,是的。你是说你在一个“单线程”的公寓里。只有另一个线程可以重置事件。如果只能有一个线程,则会出现死锁。使用多线程单元。@ken2k我不能使用
任务
,因为我使用.net 3.5,而另一个解决方案“由
任务
类解决,它只由.net 4.0或4.5使用。@PeterRitchie现在您在问题中添加了这个精度,请查看我的答案。谢谢您的帮助:),谢谢你的帮助:)请检查我的编辑。有没有可能这可以转换成原始问题-我会在那里投票:P(obv带有“仅当3.5”的但书,可以说是最古老的问题:)
// No MaxHandle limitation ;)
for (var offset = 0; offset <= count; offset++)
{
    // Initialize the reset event
    var resetEvent = new ManualResetEvent();

    // Queue action in thread pool for each item in the list
    int counter = count;
    foreach (var item in list)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback((object data) =>
                      {
                          int methodIndex =
                              (int) ((object[]) data)[0];

                          // Execute the method and pass in the enumerated item
                          action((T) ((object[]) data)[1]);

                          // Decrements counter atomically
                          Interlocked.Decrement(ref counter);

                          // If we're at 0, then last action was executed
                          if (Interlocked.Read(ref counter) == 0)
                          {
                              resetEvent.Set();
                          }
                      }), new object[] {i, item});
    }

    // Wait for the single WaitHandle
    // which is only set when the last action executed
    resetEvent.WaitOne();
}
// No MaxHandle limitation ;)
for (var offset = 0; offset <= count; offset++)
{
    // Initialize the reset event
    var resetEvent = new ManualResetEvent(false);

    // Queue action in thread pool for each item in the list
    long counter = count;
    // use a thread for each item in the chunk
    int i = 0;
    foreach (var item in list)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback((object data) =>
                      {
                          int methodIndex =
                              (int) ((object[]) data)[0];

                          // Execute the method and pass in the enumerated item
                          action((T) ((object[]) data)[1]);

                          // Decrements counter atomically
                          Interlocked.Decrement(ref counter);

                          // If we're at 0, then last action was executed
                          if (Interlocked.Read(ref counter) == 0)
                          {
                              resetEvent.Set();
                          }
                      }), new object[] {i, item});
    }

    // Wait for the single WaitHandle
    // which is only set when the last action executed
    resetEvent.WaitOne();
}