获取Parallel.Foreach

时间:2016-01-15 12:28:38

标签: c# multithreading command task-parallel-library deadlock

我有一个命令队列。一个线程正在尝试执行这些命令。

其他线程可以要求暂停执行(并且它们将被阻止,直到当前命令执行完成),并恢复它们。

当线程想要执行thws命令时(以固定间隔),它会标记它想要执行命令(并且在被删除所有“暂停”之前被阻塞。

唯一的问题是某些命令可能会尝试暂停命令执行(因为某些事件会侦听其他事件,...)。

到目前为止它的处理方式是存储执行命令的线程的ThreadId,如果来自此线程,则忽略暂停请求。 (你知道,你不必告诉我这是一个简洁的设计,但我会用它来做:()。

一个类包含所有这些CommandQueue逻辑:

public void PauseDataCommandProcessing()
{
    if (Thread.CurrentThread.ManagedThreadId == m_processDataCommandThreadId)
    {
        return;
    }
    lock (m_pauseLock)
    {
        m_pauseCounter++;
        if (m_dataCommandInProgress)
        {
            Monitor.Wait(m_pauseLock);
        }
    }
}


public void ResumeDataCommandProcessing()
{
    if (Thread.CurrentThread.ManagedThreadId == m_processDataCommandThreadId)
    {
        return;
    }
    lock (m_pauseLock)
    {
        m_pauseCounter--;
        if (m_pauseCounter == 0)
        {
            Monitor.PulseAll(m_pauseLock);
        }
    }
}

//Thoses methods are called by the command executers
public void FlagCommandsExecutionInProgress()
{
    m_processDataCommandThreadId = Thread.CurrentThread.ManagedThreadId;
    lock (m_pauseLock)
    {
        while (m_pauseCounter > 0)
        {
            Monitor.Wait(m_pauseLock);
        }
        m_dataCommandInProgress = true;
    }
}

public void FlagCommandsExecutionFinished()
{
    lock (m_pauseLock)
    {
        m_dataCommandInProgress = false;
        Monitor.PulseAll(m_pauseLock);
    }
}

这是我基本上执行它们的方式

CommandContainer.FlagCommandsExecutionInProgress();
try{
    IEnumerable<CommandInfo> commandSet =CommandContainer.RetrieveCommands();//Get the current commands list
    foreach (CommandInfo command in commandSet){
        command.Execute();
    }
}finally{
    CommandContainer.FlagCommandsExecutionFinished();
}

为了提高执行命令的速度,我想通过“Target”重新组合命令(每个命令应用于特定对象),然后并行执行每组命令。

想法是这样执行它们:

CommandContainer.FlagCommandsExecutionInProgress();
try{
    IEnumerable<IGrouping<object, CommandInfo>>  groupedCommandSet =CommandContainer.RetrieveCommands().GroupBy(c=>c.Target);//Get the current commands list
    Parallel.ForEach(groupedCommandSet,commandSet=>{
        foreach (CommandInfo command in commandSet){
            command.Execute();
        }
    } );
}finally{
    CommandContainer.FlagCommandsExecutionFinished();
}

但不幸的是,他们会有一个不同的ThreadId,我会遇到一些僵局,因为他们会等待自己完成。

假设我无法改变这些暂停的方式,你有没有办法解决我的问题?

1 个答案:

答案 0 :(得分:0)

我最后这样做了:我不知道是否有更好的解决方案,但似乎有效:

private HashSet<int> m_processDataCommandThreadIds = new HashSet<int>();

public void PauseDataCommandProcessing()
{
    if (m_processDataCommandThreadIds.Contains(Thread.CurrentThread.ManagedThreadId))
    {
        return;
    }
    lock (m_pauseLock)
    {
        m_pauseCounter++;
        if (m_dataCommandInProgress)
        {
            Monitor.Wait(m_pauseLock);
        }
    }
}


public void ResumeDataCommandProcessing()
{
    if (m_processDataCommandThreadIds.Contains(Thread.CurrentThread.ManagedThreadId))
    {
        return;
    }
    lock (m_pauseLock)
    {
        m_pauseCounter--;
        if (m_pauseCounter == 0)
        {
            Monitor.PulseAll(m_pauseLock);
        }
    }
}

//Thoses methods are called by the command executers
public void FlagCommandsExecutionInProgress()
{
    m_processDataCommandThreadIds.Add(Thread.CurrentThread.ManagedThreadId);
    lock (m_pauseLock)
    {
        while (m_pauseCounter > 0)
        {
            Monitor.Wait(m_pauseLock);
        }
        m_dataCommandInProgress = true;
    }
}

public void FlagCommandsExecutionFinished()
{
    m_processDataCommandThreadIds.Remove(Thread.CurrentThread.ManagedThreadId);
    lock (m_pauseLock)
    {
        m_dataCommandInProgress = false;
        Monitor.PulseAll(m_pauseLock);
    }
}