Как отследить ошибку синхронизации? - PullRequest
0 голосов
/ 11 марта 2011

Я недавно сделал мою простую графическую библиотеку многопоточной. Теперь это быстрее - и симуляция сильно дрожит, как если бы разные места кэшировали старые данные позиции и затем применяли их после того, как они стали «устаревшими».

По сути, ящики двигаются, затем дергаются назад, затем двигаются, затем дергаются назад ... Пока еще нет столкновений, так что это не так.

Не уверен, какой код отправлять.

Спасибо.

Редактировать: Что бы это ни было, оно также вызывает скачки задержки.

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();
    }
}

Основной цикл обновления:

    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();
    }

Ответы [ 2 ]

0 голосов
/ 11 марта 2011

Если данные «устаревают», то вам нужно исправить свою систему кэширования для удаления / обновления старых данных.

Потоки действительно не так сложны, логика проста.Проблема с многопоточностью заключается в определении ваших данных, которые являются общими и не общими, отслеживания этих данных и убедитесь, что эти данные обновляются в правильном порядке.Большая часть этого связана со структурой вашей программы.Структура намного важнее, когда вы добавляете потоки в вашу программу.

0 голосов
/ 11 марта 2011

Как вы управляете данными, можете ли вы проверить их в момент считывания, чтобы определить, устарели ли они? Предоставление рекомендаций по многопоточному приложению довольно сложно. Вы можете попробовать настроить трассировку и записать конкретные фрагменты, где, по вашему мнению, может быть проблема. Если вы вошли в систему, когда данные изменяются и когда они читаются, вы можете выяснить, где они идут не так.

Разместите пример кода, чтобы показать нам, как вы управляете данными, и мы можем взять их оттуда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...