Почему пул потоков может запускать мои задачи с тем же приоритетом, а не в том порядке, в котором я их разместил? - PullRequest
0 голосов
/ 28 апреля 2018

Я последовательно запускаю три операции через пул потоков. У них одинаковый приоритет. Однако порядок их исполнения не всегда тот, в котором я их запускал. Почему это происходит?

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

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace ThreadsLearning {

    class Foo {
        public string Name { get; set; }

        public override string ToString() {
            return Name;
        }
    }

    class Program {

        private static void Main(string[] args) {

            Console.WriteLine("Main method works...");

            Foo foo = new Foo { Name = "Bob" };

            CallContext.LogicalSetData("name", foo);

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("1: Name = {0}",
            CallContext.LogicalGetData("name")));

            ExecutionContext.SuppressFlow();

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("2: Name = {0}",
                CallContext.LogicalGetData("name")));

            ExecutionContext.RestoreFlow();

            ThreadPool.QueueUserWorkItem(state => Console.WriteLine("3: Name = {0}",
                CallContext.LogicalGetData("name")));

            Console.WriteLine("Hit <Enter> for exit...");
            Console.ReadLine();
        }
    }
}

Выход может быть:

Main method works...
Hit <Enter> for exit...
2: Name =
1: Name = Bob
3: Name = Bob

или

Main method works...
1: Name = Bob
2: Name =
3: Name = Bob
Hit <Enter> for exit...

UPD

Я попытался сделать то же самое с потоком и получить ту же проблему:

using System;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace ThreadsLearning {

    class Foo {
        public string Name { get; set; }

        public override string ToString() {
            return Name;
        }
    }

    class Program {

        private static void Main(string[] args) {

            using (MemoryStream ms = new MemoryStream()) {

                using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8, 0x1000, true)) {
                    sw.WriteLine("Main method works...");

                    Foo foo = new Foo { Name = "Bob" };

                    CallContext.LogicalSetData("name", foo);

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("1: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    ExecutionContext.SuppressFlow();

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("2: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    ExecutionContext.RestoreFlow();

                    ThreadPool.QueueUserWorkItem(state => sw.WriteLine("3: Name = {0}",
                        CallContext.LogicalGetData("name")));

                    Thread.Sleep(2000); // Postpone the ws.Dispose() call.
                }

                using (StreamReader sr = new StreamReader(ms, Encoding.UTF8)) {
                    Console.WriteLine("Stream length: {0} bytes", ms.Length);
                    ms.Position = 0;
                    Console.WriteLine("Data: \n{0}", sr.ReadToEnd());
                }
            }

            Console.WriteLine("Hit <Enter> for exit...");
            Console.ReadLine();
        }
    }
}

1 Ответ

0 голосов
/ 28 апреля 2018

Threadpool использует Очередь, чтобы вводить "вещи, которые нужно сделать" и извлекать "вещи, которые нужно делать".

при добавлении задачи она помещается в доступный слот, просто посмотрите на окно протектора в Visual Studio, вы увидите, что это не очередь, а массив фиксированного размера (может увеличиваться, если становится больше ) Смотрите изображение из "JustDecompile"

Pushing a storage structure holding your action on the

Если ваша логика требует выполнения шага 1, а затем шага 2, вы не можете использовать этот метод, природа «многопоточности» заключается в том, что вы запускаете что-то в фоновом режиме, которое в некотором роде является изолированным, «оператор работы» ", работает как задумано, запускает задачу, как только становятся доступными ресурсы.

Глядя на это поведение, вы получите ожидаемый поток Task.ContinueWith (action) , вы можете связать действия вместе, как показано здесь .

...