Как выполнить код в указанном потоке

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

Мне не нужны инфраструктурные вещи, такие как SynchronizationContext, я хочу знать способы достижения этого поведения вручную.

Ответ 1

Чтобы выполнить что-то в указанном потоке, вам понадобится этот поток, чтобы выполнить работу, например, из синхронизированной очереди. Это может быть делегат или известный тип с каким-то способом Execute(). В случае интерфейсов пользовательского интерфейса также обычно можно напрямую (или косвенно) добавлять работу к основным потокам (через очереди сообщений) - например, Control.Invoke или Dispatcher.Invoke.

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

Ответ 2

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

class Program
{
    static void Main(string[] args)
    {
        var c = new System.Collections.Concurrent.BlockingCollection<Tuple<bool, Action>>();
        var t = new Thread(() =>
        {
            while (true)
            {
                var item = c.Take();
                if (!item.Item1) break;
                item.Item2();
            }
            Console.WriteLine("Exiting thread");
        });
        t.Start();

        Console.WriteLine("Press any key to queue first action");
        Console.ReadKey();
        c.Add(Tuple.Create<bool, Action>(true, () => Console.WriteLine("Executing first action")));

        Console.WriteLine("Press any key to queue second action");
        Console.ReadKey();
        c.Add(Tuple.Create<bool, Action>(true, () => Console.WriteLine("Executing second action")));

        Console.WriteLine("Press any key to stop the thread");
        Console.ReadKey();
        c.Add(Tuple.Create<bool, Action>(false, null));

        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}

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

Ответ 3

Вы можете использовать Dispatcher, по крайней мере, если вы находитесь на .NET 4.

Ответ 4

Большой вопрос - почему вы хотели бы этого.

Поток, о котором идет речь, должен будет сотрудничать, опросить очередь или что-то в этом роде. Это почти никогда не стоит усилий, поэтому поддержки для него мало.

Исключением является, конечно же, поток графического интерфейса. В этом случае используйте SyncContext throuhg Control.Invoke или Dispatcher.Invoke.