Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#多个可重用工作线程_C#_Multithreading - Fatal编程技术网

C#多个可重用工作线程

C#多个可重用工作线程,c#,multithreading,C#,Multithreading,我正在尝试用可重用的工作线程构建某种多线程游戏引擎。这意味着工作人员正在运行一个无休止的循环,并且在每次迭代之后,调用一个方法,该方法使用AutoResetEvent挂起线程,直到下一次迭代从外部开始。它很好用。 但是我想等待所有工作线程进入等待状态。但是在第一步中,最后一个线程总是被忽略。 这是我的代码: class WorkerThread { private readonly Game game; private readonly Task task; privat

我正在尝试用可重用的工作线程构建某种多线程游戏引擎。这意味着工作人员正在运行一个无休止的循环,并且在每次迭代之后,调用一个方法,该方法使用
AutoResetEvent
挂起线程,直到下一次迭代从外部开始。它很好用。 但是我想等待所有工作线程进入等待状态。但是在第一步中,最后一个线程总是被忽略。 这是我的代码:

class WorkerThread
{
    private readonly Game game;
    private readonly Task task;
    private readonly AutoResetEvent waitEvent;
    private readonly AutoResetEvent finishEvent;

    public string Message { get; set; }
    public bool Active { get; private set; }

    public WorkerThread(Game game)
    {
        this.game = game;
        waitEvent = new AutoResetEvent(false);
        finishEvent = new AutoResetEvent(false);
        task = new Task(startTask);
    }

    public void Start()
    {
        task.Start();
    }

    public void PerformFrame()
    {
        finishEvent.Reset();
        waitEvent.Set();
    }

    public void WaitForFrameToFinish()
    {
        finishEvent.WaitOne();
    }

    private void startTask()
    {
        WaitFrame();
        run();
    }

    long sum;
    private void run()
    {
        while (true)
        {
            sum = 0;
            for (int i = 0; i < 1000000; i++)
            {
                sum += i;
            }

            Console.WriteLine(Message);
            WaitFrame();
        }
    }

    private void WaitFrame()
    {
        Active = false;
        finishEvent.Set();
        waitEvent.WaitOne();
        Active = true;
    }
}

class Game
{
    private readonly List<WorkerThread> workers = new List<WorkerThread>();

    public Game()
    {
        workers.Add(new WorkerThread(this) { Message = "Worker 1" });
        workers.Add(new WorkerThread(this) { Message = "Worker 2" });
        workers.Add(new WorkerThread(this) { Message = "Worker 3" });
        workers.Add(new WorkerThread(this) { Message = "Worker 4" });
        workers.Add(new WorkerThread(this) { Message = "Worker 5" });
        workers.Add(new WorkerThread(this) { Message = "Worker 6" });
    }

    public void Start()
    {
        foreach (WorkerThread worker in workers)
        {
            worker.Start();
        }
    }

    public void OneFrame()
    {
        //start every worker
        foreach (WorkerThread worker in workers)
        {
            worker.PerformFrame();
        }

        //wait for the workers to finish
        foreach (WorkerThread worker in workers)
        {
            worker.WaitForFrameToFinish();
        }

        //check if there are workers still running
        foreach (WorkerThread worker in workers)
        {
            if (worker.Active)
            {
                Console.WriteLine(worker.Message + " still active");
            }
        }

        Console.WriteLine("Frame finished.\n");
    }
}
类WorkerThread
{
私人只读游戏;
私有只读任务;
私有只读自动resetEvent waitEvent;
私有只读自动存储事件finishEvent;
公共字符串消息{get;set;}
公共bool活动{get;private set;}
公共WorkerThread(游戏)
{
这个游戏=游戏;
waitEvent=新的自动重置事件(false);
finishEvent=新的自动重置事件(假);
任务=新任务(startTask);
}
公开作废开始()
{
task.Start();
}
public void PerformFrame()
{
finishEvent.Reset();
waitEvent.Set();
}
public void WaitForFrameToFinish()的
{
finishEvent.WaitOne();
}
私有无效startTask()
{
WaitFrame();
run();
}
长和;
私家车
{
while(true)
{
总和=0;
对于(int i=0;i<1000000;i++)
{
总和+=i;
}
控制台写入线(消息);
WaitFrame();
}
}
私有void WaitFrame()
{
主动=假;
finishEvent.Set();
waitEvent.WaitOne();
主动=真;
}
}
班级游戏
{
私有只读列表工作者=新列表();
公共游戏()
{
Add(newworkerThread(this){Message=“Worker 1”});
Add(newworkerThread(this){Message=“Worker 2”});
Add(newworkerThread(this){Message=“Worker 3”});
Add(newworkerThread(this){Message=“Worker 4”});
Add(newworkerThread(this){Message=“Worker 5”});
Add(newworkerThread(this){Message=“Worker 6”});
}
公开作废开始()
{
foreach(WorkerThread worker in workers)
{
worker.Start();
}
}
公共void OneFrame()
{
//启动每个工人
foreach(WorkerThread worker in workers)
{
worker.PerformFrame();
}
//等待工人们完成
foreach(WorkerThread worker in workers)
{
worker.WaitForFrameToFinish();
}
//检查是否有工人仍在运行
foreach(WorkerThread worker in workers)
{
if(worker.Active)
{
Console.WriteLine(worker.Message+“仍处于活动状态”);
}
}
Console.WriteLine(“帧完成。\n”);
}
}
有人知道为什么
游戏
不等待最后一个
工作线程
完成它的任务吗

编辑:使用
ManualResetEventSlim
而不是
AutoResetEvent
解决了问题。但我仍然不明白为什么上面的方法不起作用


编辑2:我找到了答案并发布在下面。

我刚刚找到了解决方案
startTask
使用
WaitFrame
方法设置
finishEvent
。这样,
WaitForFrameToFinish
就不会在第一次迭代中等待工作进程,因为已经设置了
finishEvent
。 如果您这样做,效果很好:

private void startTask()
{
    waitEvent.WaitOne();
    waitEvent.Reset();
    finishEvent.Reset();

    run();
}

代码对我有用。如何确定它不等待最后一个线程?调用
Game.Start()
,然后调用
Game.OneFrame()
生成以下输出:
Worker 1 Worker 2 Worker 4 Worker 3 Worker 5 Worker 6仍然活动的Frame finished。Worker 6
@Skinnix,可能来自缓存数据,您可能需要在
Active
周围设置一个内存围栏,比如将
Active
的读写操作放在
锁中,或者从自动属性切换到带有后备存储的。@ScottChamberlain听起来似乎有道理,但将
Active
属性更改为使用
Volatile。读取
Volatile.Write
似乎不会改变任何东西…@ScottChamberlain事实上,你说得很对。在进一步的实现中,内存隔离和线程安全将是一个严重的问题。我将来必须考虑这个问题。