如何追踪同步错误?

发布于 2024-10-21 07:50:25 字数 5077 浏览 2 评论 0原文

我最近将我的简单图形库设为多线程。现在速度更快了——而且模拟抖动很大,就好像各个地方缓存了旧的位置数据,然后在它“过时”后应用它。

基本上,盒子移动,然后猛拉回来,然后移动,然后猛拉回来......到目前为止还没有发生碰撞,所以不是那样的。

不确定要发布什么代码。

谢谢。

编辑:无论是什么,也会导致滞后峰值。

Edit2:

任务管理器:

public class TaskManager
{
    public delegate void MethodDel(float timestep);
    private Queue<MethodDel> queue;
    private List<TaskHandler> handlers;
    private float value;


    public float Value
    {
        get
        {
            return value;
        }
        set
        {
            this.value = value;
        }
    }


    public TaskManager()
    {
        this.queue = new Queue<MethodDel>();
        this.handlers = new List<TaskHandler>(System.Environment.ProcessorCount);

        for (int t = 0; t < this.handlers.Capacity; ++t)
            this.handlers.Add(new TaskHandler(this));

        foreach (var handler in handlers)
            handler.Start();

        this.value = 0;
    }


    public void Start()
    {
        foreach (var handler in handlers)
            handler.Wake();
    }


    public void Stop()
    {
        lock (queue)
            queue.Clear();

        foreach (var handler in handlers)
            handler.StopWhenDone();
    }


    public void StopWhenDone()
    {
        foreach (var handler in handlers)
            handler.StopWhenDone();
    }


    public void AddToQueue(MethodDel method)
    {
        lock (queue)
            queue.Enqueue(method);
    }


    public bool GetFromQueue(out MethodDel method)
    {
        lock (queue)
        {
            if (queue.Count == 0) { method = null; return false; }

            method = queue.Dequeue();
            return true;
        }
    }


    public int GetQueueCount()
    {
        return queue.Count;
    }

    public void Wait()
    {
        // Have to wait for them one at a time because the main thread is STA.

        WaitHandle[] waitHandles = new WaitHandle[1];
        // for (int t = 0; t < handlers.Count; ++t) waitHandles[t] = handlers[t].WaitHandle;

        // WaitHandle.WaitAll(waitHandles);
        for (int t = 0; t < handlers.Count; ++t) { waitHandles[0] = handlers[t].WaitHandle; WaitHandle.WaitAll(waitHandles); }
    }
}

任务处理程序:

public class TaskHandler
{
    private TaskManager manager;
    private Thread thread;
    private bool stopWhenDone;
    private ManualResetEvent waitHandle;


    public ManualResetEvent WaitHandle
    {
        get
        {
            return waitHandle;
        }
    }


    public TaskHandler(TaskManager manager)
    {
        this.manager = manager;
    }


    public void Start()
    {
        waitHandle = new ManualResetEvent(false);

        stopWhenDone = false;

        thread = new Thread(Run);
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.MTA);
        thread.Start();
    }


    public void StopWhenDone()
    {
        this.stopWhenDone = true;
    }


    private void Run()
    {
        TaskManager.MethodDel curMethod;
        while (true)
        {
            while (!stopWhenDone || manager.GetQueueCount() > 0)
            {
                if (manager.GetFromQueue(out curMethod))
                {
                    curMethod(manager.Value);
                }
            }
            waitHandle.Set();
            waitHandle.WaitOne();
        }
    }


    public void Wake()
    {
        waitHandle.Set();
    }
}

主更新循环:

    public virtual void Update(float timestep)
    {
        taskManager.Value = timestep; taskManager.Start();

        foreach (Camera camera in cameraLookup.Values)
            // camera.Update(timestep);
            taskManager.AddToQueue(camera.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        /* foreach (IAffector affector in affectorLookup.Values)
            affector.Update(timestep); */

        foreach (IAffector affector in affectorLookup.Values)
            taskManager.AddToQueue(affector.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        // taskManager.StopWhenDone();
        // taskManager.Wait();

        foreach (IConstraint constraint in constraintLookup.Values)
            // constraint.Update(timestep);
            taskManager.AddToQueue(constraint.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Physic physic in physicLookup.Values)
            // physic.Update(timestep);
            taskManager.AddToQueue(physic.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Body body in bodyLookup.Values)
            // body.Update(timestep);
            taskManager.AddToQueue(body.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Model model in modelLookup.Values)
            // model.Update(timestep);
            taskManager.AddToQueue(model.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();
    }

I've recently made my simple graphics library multi-threaded. It is now faster - And the simulation jitters a lot, as if various places had cached old position data and then applied it after it had gone "stale".

Basically, the boxes move, then jerk back, then move, then jerk back...There's no collision as of yet, so it's not that.

Not sure what code to post.

Thanks.

Edit: Whatever it is, also causes lag spikes.

Edit2:

TaskManager:

public class TaskManager
{
    public delegate void MethodDel(float timestep);
    private Queue<MethodDel> queue;
    private List<TaskHandler> handlers;
    private float value;


    public float Value
    {
        get
        {
            return value;
        }
        set
        {
            this.value = value;
        }
    }


    public TaskManager()
    {
        this.queue = new Queue<MethodDel>();
        this.handlers = new List<TaskHandler>(System.Environment.ProcessorCount);

        for (int t = 0; t < this.handlers.Capacity; ++t)
            this.handlers.Add(new TaskHandler(this));

        foreach (var handler in handlers)
            handler.Start();

        this.value = 0;
    }


    public void Start()
    {
        foreach (var handler in handlers)
            handler.Wake();
    }


    public void Stop()
    {
        lock (queue)
            queue.Clear();

        foreach (var handler in handlers)
            handler.StopWhenDone();
    }


    public void StopWhenDone()
    {
        foreach (var handler in handlers)
            handler.StopWhenDone();
    }


    public void AddToQueue(MethodDel method)
    {
        lock (queue)
            queue.Enqueue(method);
    }


    public bool GetFromQueue(out MethodDel method)
    {
        lock (queue)
        {
            if (queue.Count == 0) { method = null; return false; }

            method = queue.Dequeue();
            return true;
        }
    }


    public int GetQueueCount()
    {
        return queue.Count;
    }

    public void Wait()
    {
        // Have to wait for them one at a time because the main thread is STA.

        WaitHandle[] waitHandles = new WaitHandle[1];
        // for (int t = 0; t < handlers.Count; ++t) waitHandles[t] = handlers[t].WaitHandle;

        // WaitHandle.WaitAll(waitHandles);
        for (int t = 0; t < handlers.Count; ++t) { waitHandles[0] = handlers[t].WaitHandle; WaitHandle.WaitAll(waitHandles); }
    }
}

TaskHandler:

public class TaskHandler
{
    private TaskManager manager;
    private Thread thread;
    private bool stopWhenDone;
    private ManualResetEvent waitHandle;


    public ManualResetEvent WaitHandle
    {
        get
        {
            return waitHandle;
        }
    }


    public TaskHandler(TaskManager manager)
    {
        this.manager = manager;
    }


    public void Start()
    {
        waitHandle = new ManualResetEvent(false);

        stopWhenDone = false;

        thread = new Thread(Run);
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.MTA);
        thread.Start();
    }


    public void StopWhenDone()
    {
        this.stopWhenDone = true;
    }


    private void Run()
    {
        TaskManager.MethodDel curMethod;
        while (true)
        {
            while (!stopWhenDone || manager.GetQueueCount() > 0)
            {
                if (manager.GetFromQueue(out curMethod))
                {
                    curMethod(manager.Value);
                }
            }
            waitHandle.Set();
            waitHandle.WaitOne();
        }
    }


    public void Wake()
    {
        waitHandle.Set();
    }
}

The main Update loop:

    public virtual void Update(float timestep)
    {
        taskManager.Value = timestep; taskManager.Start();

        foreach (Camera camera in cameraLookup.Values)
            // camera.Update(timestep);
            taskManager.AddToQueue(camera.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        /* foreach (IAffector affector in affectorLookup.Values)
            affector.Update(timestep); */

        foreach (IAffector affector in affectorLookup.Values)
            taskManager.AddToQueue(affector.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        // taskManager.StopWhenDone();
        // taskManager.Wait();

        foreach (IConstraint constraint in constraintLookup.Values)
            // constraint.Update(timestep);
            taskManager.AddToQueue(constraint.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Physic physic in physicLookup.Values)
            // physic.Update(timestep);
            taskManager.AddToQueue(physic.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Body body in bodyLookup.Values)
            // body.Update(timestep);
            taskManager.AddToQueue(body.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();

        foreach (Model model in modelLookup.Values)
            // model.Update(timestep);
            taskManager.AddToQueue(model.Update);

        taskManager.StopWhenDone();
        taskManager.Wait();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

草莓酥 2024-10-28 07:50:25

您如何管理数据,您可以在读取数据时进行测试以判断数据是否过时吗?提供有关多线程应用程序的建议非常困难。您可以尝试设置一些跟踪并记录您认为可能存在问题的特定部分。如果您记录了数据更改和读取的时间,您也许能够找出哪里出了问题。

发布一些示例代码,向我们展示如何管理数据,我们可以从那里获取数据。

How are you managing the data, can you test at the point it is read to tell if it is stale? Providing advice on a multi-threaded app is pretty difficult. You could try setting up some tracing and log the specific pieces where you think the problem might be. If you logged when data is changed and when it is read you might be able to figure out where it is going wrong.

Post some example code to show us how you manage the data and we can take it from there.

岁月如刀 2024-10-28 07:50:25

如果数据变得“过时”,那么您需要修复缓存系统以驱逐/更新旧数据。

线程其实并不难,逻辑很简单。线程的问题是识别共享和未共享的数据,跟踪这些数据,并确保这些数据以正确的顺序更新。其中大部分与程序的结构有关。当您将线程添加到程序中时,结构就变得更加重要。

If the data is going "stale", then you need to fix your caching system to evict/update old data.

Threading really isn't that hard, the logic is simple. The problem with threading is identifying your data that is shared and not shared, tracking this data, and make sure this data is updated in the correct order. Most of this has to do with your program's structure. Structure is much much more important when you add threads into your program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文