Как на основе CancellationToken сделать 2 CancellationToken ?

Pruvetik
Дата: 29.05.2014 19:39:31
Привет.

Мне нужно, чтобы два объекта останавливались последовательно, в строго определенном порядке.
Просто первый из них обращается ко второму, и нужно защитится от ситуации, что второй остановится раньше (многопоточность же), а первый успеет обратится ко второму, обратившись по null адресу.

Оба эти объекта создаются внешним объектом (в его конструкторе).

Можно ли как-то разделить CancellationToken на 2 отдельных CancellationToken и их уже передать в порождаемые классы ?
Я не увидел у CancellationToken каких-то событий, к которым бы можно было подцепится.

Как быть ?
Где-то в степи
Дата: 29.05.2014 20:22:43
Pruvetik,
мне кажется Вы не догоняете немного
автор
Можно ли как-то разделить CancellationToken на 2 отдельных CancellationToken

получайте CancellationToken из фабрики CancellationTokenSource вы там можете получить их хоть сколько
в виде структуры и распихать по потокам
кде в потоке они будут сидеть в конце работы в виде
  bool run = true;
                           while (run)
                           {
                               if (((CancellationToken)st).IsCancellationRequested)
                               {
                                   run = false;
                               }
                           }
Pruvetik
Дата: 29.05.2014 20:27:12
Где-то в степи,

Из какой фабрики получать ?
Pruvetik
Дата: 29.05.2014 20:29:51
Pruvetik,

Я хочу уточнить, что никто извне класса не знает, что он там внутри себя создает еще 2 подкласса.

В принципе я могу переделать код как угодно. Но что тогда предавать в класс ? Сейчас передаю CancellationTokenSource - и используется его свойство Token.

Что еще можно передать, чтобы класс мог разделить на отдельные токены и вызывать их в нужной последовательности ?
Где-то в степи
Дата: 29.05.2014 20:31:02
Pruvetik, минутку
Где-то в степи
Дата: 29.05.2014 20:36:21
 class Program
    {
        static void Main(string[] args)
        {
            var s = new CancellationTokenSource();
          
            new Thread(st =>
                       {
                           while (!((CancellationToken)st).IsCancellationRequested)
                               ;

                           Console.Write("stop1");
                       }).Start(s.Token);

            new Thread(st =>
                       {
                           var i = 0;
                           while (i < 2000000000) i++;
                           ((CancellationTokenSource)st).Cancel();
                           Console.Write("stop2");
                       }).Start(s);
            Console.Read();
        }
    }
Pruvetik
Дата: 29.05.2014 20:54:21
Где-то в степи,

Нет. У меня другое.
И честно говоря, уже появилась идея, что нужно делать.

У меня вот, что:

    public class MainClass
    {
        private WorkerClass class1;
        private WorkerClass class2;

        public MainClass(CancellationTokenSource cts)
        {
            class1 = new WorkerClass(cts);
            class2 = new WorkerClass(cts);
        }
    }


Сейчас оба класса мониторят один и тот же cts.
Следовательно порядок их останова - совершенно случаен.

Мне же нужно, чтобы обязательно был остановлен сначала class1 , а потом class2.


В общем. Я уже понимаю, что мне нужно сделать.
Нужно чтобы MainClass прослушивал переданный cts - и создал два новых CancellationTokenSource , и их уже передал в class1 и class2 соответственно.
И когда сработает оригинальный cts, MainClass вызовет cancel в нужном порядке у двух созданных CancellationTokenSource. Все выйдет замечательно.

Че то голова уже под вечер не варит. В принципе так и нужно было сразу сделать. Но Вам спасибо за помощь в любом случае !
Где-то в степи
Дата: 29.05.2014 21:06:35
Pruvetik,
если честно, мне не очень нравится реализация с этим кооперативным шлагбаумом.
я бы сделал проще два делегата as два потока из пула
а управлять то ими одно удовольствие: хош из первого результат второго вызови - хош наоборот..
Где-то в степи
Дата: 29.05.2014 21:17:10
Еще мне не нравится вся озабоченность временем выполнения потока, передавайте в поток указатель на функцию
и выводите через нее результат наружу, или еще как , поток должен умереть после работы, а не плющить процессор в ожидании команды.
Pruvetik
Дата: 29.05.2014 21:28:13
Где-то в степи,

Спасибо за предложение.

Но я планировал уже с TPL все организовать. Мне это кажется сейчас проще, чем с обычными тредами.
Каждый из классов WorkerClass - это тоже отдельный поток ведь.
Нужно не забывать про возникающие исключения. А в Task'ах с ними просто работать.

Даже если делать через треды, суть не меняется - мне обязательно нужно, чтобы сначала один завершился, а потом второй.

Я сделаю это примерно так:

cts1.cancel ();
// class1 обращается к class2 - поэтому его нужно остановится первым
try
{
class1.Wait(); // Ждем, чтобы класс точно завершился
}
catch (Exception Exe)
{
...
}
finally
{
  cts2.cancel();
  class2.Wait();
}


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

А с тредами получится ли ? Ну если только через лямбды да Action'ы наверное.

В общем TPL мне видится более чистым (с точки зрения кучи кода) решением.