Вызвать метод в произвольном потоке - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть сценарий, в котором у меня есть основной поток, который использует целый ряд других потоков из пула потоков, которые выполняют некоторую работу.

В основном потоке я использую объект, который не является потокобезопасным (сторонний компонент, поэтому изменить это невозможно). Потоки потоков должны вызывать методы для этого не поточно-безопасного объекта. В основном потоке у меня есть объект, представляющий поток, в котором объявлен сторонний компонент:

private ThirdPartyComponent third_party_component;
private Thread mainThread;

В методе инициализации основного потока я сохраняю ссылку на «безопасный» поток для доступа сторонний компонент:

mainThread = Thread.CurrentThread;

Я пытаюсь создать какой-то метод, который будет «отправлять» вызов стороннего компонента в правильный поток, что-то вроде этого:

private void DoTheWork()
{
    if(Thread.CurrentThread != mainThread)
    {
         mainThread.Invoke( () => { third_party_component.DoItThreadSafe(); } );
    }
}

Я регулярно использовал этот шаблон для обновления кода пользовательского интерфейса в главном потоке, используя Control.Invoke, но у сохраненного мной объекта Thread (mainThread) нет метода Invoke.

Есть ли что-то особенное в потоке пользовательского интерфейса, позволяющее это осуществить? Или я что-то упустил в объекте Thread? Каков наилучший способ заставить DoTheWork() работать в основном потоке?

(Редактировать: FWIW в этом приложении mainThread будет основным потоком Winforms GUI, но я надеюсь найти решение, которое работает в любом потоке и не зависит от основного потока, являющегося потоком GUI.

1 Ответ

2 голосов
/ 15 апреля 2020

Обычно, когда речь идет о не поточных объектах, это просто означает, что он не может быть вызван несколькими потоками одновременно. Если это так, то можно просто заблокировать объект, не поддерживающий поток, и вызывать его из любого потока, который вы используете.

Можно записывать объекты, которые могут быть вызваны только потоком, создавшим поток объектов. Если это так, возможно, что-то подобное может сработать:

public class TaskManager<T>
{
    private readonly Func<T> constructor;
    private BlockingCollection<Action<T>> queue = new BlockingCollection<Action<T>>(new ConcurrentQueue<Action<T>>());

    public TaskManager(Func<T> constructor)
    {
        this.constructor = constructor;
        var thread = new Thread(ThreadMain);
        thread.Start();
    }

    private void ThreadMain()
    {
        var obj = constructor();
        foreach(var action in queue.GetConsumingEnumerable())
        {
            action(obj);
        }
    }

    public void ScheduleWork(Action<T> work) => queue.Add(work);
    public void CompleteAdding() => queue.CompleteAdding();
}

Отказ от ответственности: не тестировалось, нет обработки ошибок, нет обработки одноразовых предметов и т. Д. c.

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