С# многопоточность
От: Roman039  
Дата: 11.04.12 07:01
Оценка: :)
Добрый день.
Есть приложение в котором надо организовать два процесса (или потока): один основной, второй дополнительный. Дополнительный поток не ограничивается выполнением одной операции. Он должен "жить" на протяжении всей работы приложения. Он должен при обработке одного из своих внутренних событий: сигнализировать основному потоку о произошедшем событии и приостановить свою работу пока не будет получен ответ от основного потока. С приостановками работы все понятно (через WaitEventHandler). Вопрос с передачей управления между потоками. Вообщем вопрос: как можно из дополнительного потока передать сигнал в основной поток, так чтобы следующие действия выполнялись именно в основном потоке?
Re: С# многопоточность
От: Victor Hytyk Украина  
Дата: 11.04.12 07:22
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Добрый день.

R>Есть приложение в котором надо организовать два процесса (или потока): один основной, второй дополнительный. Дополнительный поток не ограничивается выполнением одной операции. Он должен "жить" на протяжении всей работы приложения. Он должен при обработке одного из своих внутренних событий: сигнализировать основному потоку о произошедшем событии и приостановить свою работу пока не будет получен ответ от основного потока. С приостановками работы все понятно (через WaitEventHandler). Вопрос с передачей управления между потоками. Вообщем вопрос: как можно из дополнительного потока передать сигнал в основной поток, так чтобы следующие действия выполнялись именно в основном потоке?

двойной AutoResetEvent, один в основном потоке, другой в дополнительном. Подробнее в статье
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/
, глава AutoResetEvent (подглава "получите и распишитесь").
-----------------------------------------
тут может быть ваша реклама
Re: С# многопоточность
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 11.04.12 07:23
Оценка: +1
Здравствуйте, Roman039, Вы писали:

R>Добрый день.

R>Есть приложение в котором надо организовать два процесса (или потока): один основной, второй дополнительный. Дополнительный поток не ограничивается выполнением одной операции. Он должен "жить" на протяжении всей работы приложения. Он должен при обработке одного из своих внутренних событий: сигнализировать основному потоку о произошедшем событии и приостановить свою работу пока не будет получен ответ от основного потока. С приостановками работы все понятно (через WaitEventHandler). Вопрос с передачей управления между потоками. Вообщем вопрос: как можно из дополнительного потока передать сигнал в основной поток, так чтобы следующие действия выполнялись именно в основном потоке?

Использовать очередь (producer/consumer).
Основной поток это UI поток?
Re[2]: С# многопоточность
От: Roman039  
Дата: 11.04.12 07:33
Оценка:
Здравствуйте, Victor Hytyk, Вы писали:

VH>двойной AutoResetEvent, один в основном потоке, другой в дополнительном. Подробнее в статье
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/
, глава AutoResetEvent (подглава "получите и распишитесь").

Сейчас перечитаю еще раз эту главу... спасибо
Re[2]: С# многопоточность
От: Roman039  
Дата: 11.04.12 07:34
Оценка:
Здравствуйте, achmed, Вы писали:

A>Использовать очередь (producer/consumer).

A>Основной поток это UI поток?

Можно поподробнее или ссылочку.
Да, основной поток это UI.
Re: С# многопоточность
От: HowardLovekraft  
Дата: 11.04.12 07:38
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Дополнительный поток не ограничивается выполнением одной операции. Он должен "жить" на протяжении всей работы приложения.

Зачем?
Re[2]: С# многопоточность
От: Roman039  
Дата: 11.04.12 07:49
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Roman039, Вы писали:


R>>Дополнительный поток не ограничивается выполнением одной операции. Он должен "жить" на протяжении всей работы приложения.

HL>Зачем?
Он является постоянной составляющей работы всего приложения.
Этот поток должен контролировать работу внешнего компонента. Если во внешнем компоненте возникает "вопрос" поток должен сигнализировать основному потоку и дождаться ответа на этот "вопрос" (при этом надо приостановить работу внешнего компонента).
Re[3]: С# многопоточность
От: HowardLovekraft  
Дата: 11.04.12 07:54
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Этот поток должен контролировать работу внешнего компонента. Если во внешнем компоненте возникает "вопрос" поток должен сигнализировать основному потоку и дождаться ответа на этот "вопрос" (при этом надо приостановить работу внешнего компонента).

Тема жизни потока на протяжении всей работы приложения не раскрыта. Ожидать возникновения "вопроса" во внешнем компоненте можно по событию, после чего брать поток из пула. Иначе получится поток, который бОльшую часть времени будет тупо спать.
Re[4]: С# многопоточность
От: Roman039  
Дата: 11.04.12 08:03
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Roman039, Вы писали:


R>>Этот поток должен контролировать работу внешнего компонента. Если во внешнем компоненте возникает "вопрос" поток должен сигнализировать основному потоку и дождаться ответа на этот "вопрос" (при этом надо приостановить работу внешнего компонента).

HL>Тема жизни потока на протяжении всей работы приложения не раскрыта. Ожидать возникновения "вопроса" во внешнем компоненте можно по событию, после чего брать поток из пула. Иначе получится поток, который бОльшую часть времени будет тупо спать.

Ожидание "вопроса" и происходит по событию. Сложность в том чтобы остановить выполнение работы компонента до момента получения ответа (а ответ придет из UI). Поток бОльшую часть времени спать не будет, потому что все приложение это своеобразная "оболочка" для этого компонента.
Re[5]: С# многопоточность
От: HowardLovekraft  
Дата: 11.04.12 08:37
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Сложность в том чтобы остановить выполнение работы компонента до момента получения ответа (а ответ придет из UI).

Какое отношение остановка работы компонента имеет к многопоточности?

Если компонент предоставляет событие (в смысле C# event, а не примитив синхронизации), то, если при наступлении события обработчики вызываются компонентом синхронно, никакой проблемы нет и необходимости в дополнительном протоке нет, т.к. возможны два варианта:
1) компонент генерирует события в UI-потоке; ваш обработчик вызовется в UI-потоке, следовательно, компонент будет ждать, пока обработчик не завершит работу;
2) компонент генерирует события в фоновом потоке; ваш обработчик вызовется в фоновом потоке, следовательно, вы используете в обработчике нужный котекст синхронизации, который остановит фоновый поток, пока не выполнится ваш код из UI-потока.

Если компонент при наступлении события вызывает обработчики асинхронно (что вряд ли), то без каких-либо дополнительных средств, предоставляемых компонентом для остановки его работы, вы эту задачу не решите. И не важно при этом, сколько будет у вас потоков.
Re[6]: С# многопоточность
От: Roman039  
Дата: 11.04.12 09:03
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Roman039, Вы писали:


R>>Сложность в том чтобы остановить выполнение работы компонента до момента получения ответа (а ответ придет из UI).

HL>Какое отношение остановка работы компонента имеет к многопоточности?

HL>Если компонент предоставляет событие (в смысле C# event, а не примитив синхронизации), то, если при наступлении события обработчики вызываются компонентом синхронно, никакой проблемы нет и необходимости в дополнительном протоке нет, т.к. возможны два варианта:

HL>1) компонент генерирует события в UI-потоке; ваш обработчик вызовется в UI-потоке, следовательно, компонент будет ждать, пока обработчик не завершит работу;
HL>2) компонент генерирует события в фоновом потоке; ваш обработчик вызовется в фоновом потоке, следовательно, вы используете в обработчике нужный котекст синхронизации, который остановит фоновый поток, пока не выполнится ваш код из UI-потока.

HL>Если компонент при наступлении события вызывает обработчики асинхронно (что вряд ли), то без каких-либо дополнительных средств, предоставляемых компонентом для остановки его работы, вы эту задачу не решите. И не важно при этом, сколько будет у вас потоков.


Да, компонент генерирует событие синхронно. Я тут пришел к выводу (НЕ без помощи ответов на мой вопрос), что два потока обязательны, но они не обязательно должны работать одновременно. Так что мне вполне подходит решение с переключением конекста рабочего потока (с использованием двух экземпляров EventWaitHandler и я так понял это 2-й предложенный вариант).

Вообщем спасибо за помощь!

P.S. Первый вариант к сожалению не подходит, потому что в UI-потоке в ответ на событие будет сформирована форма вопроса для пользователя и на этом формально обработка события будет закончена, но ответа на вопрос не получено.
Re[3]: С# многопоточность
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 11.04.12 09:08
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Здравствуйте, achmed, Вы писали:


A>>Использовать очередь (producer/consumer).

A>>Основной поток это UI поток?

R>Можно поподробнее или ссылочку.


Например здесь
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/


R>Да, основной поток это UI.


В этом случае еще проще — Control.Invoke + ManulResetEvent
Re[4]: С# многопоточность
От: Roman039  
Дата: 11.04.12 09:25
Оценка:
Здравствуйте, achmed, Вы писали:

A>Здравствуйте, Roman039, Вы писали:


R>>Здравствуйте, achmed, Вы писали:


A>>>Использовать очередь (producer/consumer).

A>>>Основной поток это UI поток?

R>>Можно поподробнее или ссылочку.


A>Например здесь
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/


R>>Да, основной поток это UI.


A>В этом случае еще проще — Control.Invoke + ManulResetEvent


Я, читая эту статью, нашел и описание вами предложенного варианта. С Control'ом нельзя: UI не обязательно будет WinForms.
Re[7]: С# многопоточность
От: HowardLovekraft  
Дата: 11.04.12 10:39
Оценка:
Здравствуйте, Roman039, Вы писали:

R>с использованием двух экземпляров EventWaitHandler и я так понял это 2-й предложенный вариант

Нет.
Видимо, у меня не получается понятно объяснить.

Вот тестовый "компонент", имитирующий асинхронное получение каких-то данных:
  Скрытый текст
    internal sealed class DataArrivedEventArgs : EventArgs
    {
        private readonly Int32 data;

        public DataArrivedEventArgs(Int32 data)
        {
            this.data = data;
        }

        public Int32 Data 
        {
            get { return data; }
        }
    }

    internal sealed class MyComponent
    {
        private const Int32 dueTime = 5000;
        private readonly Timer timer;
        private readonly Random random;

        public MyComponent()
        {
            this.timer = new Timer(TimerElapsed, null, dueTime, Timeout.Infinite);
            this.random = new Random();
        }

        private void TimerElapsed(Object state)
        {
            OnDataArrived(new DataArrivedEventArgs(random.Next()));
        }

        private void OnDataArrived(DataArrivedEventArgs args)
        {
            var handler = DataArrived;
            if (handler != null)
            {
                DataArrived(this, args);
            }
            timer.Change(dueTime, Timeout.Infinite);
        }

        public event EventHandler<DataArrivedEventArgs> DataArrived;
    }


Когда доступны данные, компонент генерирует событие. Обработчики события вызываются компонентом синхронно, но в рабочем потоке из пула.
По условию задачи, нужно остановить работу компонента, оповестить UI-поток и дождаться ответа из UI-потока.
Вот код, который выполняет заданную работу:
  Скрытый текст
    public partial class Form1 : Form
    {
        private readonly MyComponent component;
        private readonly SynchronizationContext context;

        public Form1()
        {
            InitializeComponent();

            this.context = SynchronizationContext.Current;
            this.component = new MyComponent();
            this.component.DataArrived += new EventHandler<DataArrivedEventArgs>(DataArrived);
        }

        private void DataArrived(Object sender, DataArrivedEventArgs args)
        {
            context.Send(_ => textBox1.Text = args.Data.ToString(), null);
        }
    }

Выделенное полужирным можно заменить чем угодно. Это "что угодно" обладает следующими характеристиками:
— оно выполнится в UI-потоке (UI-поток оповещен и выполняет какой-то код);
— пока оно не выполнится, рабочий поток, из которого было сгенерировано событие, будет остановлен (DataArrived будет вызван из рабочего потока, но остановится на context.Send и будет ждать его завершения).

Где вы тут собираетесь использовать два потока и "два экземпляра EventWaitHandler" —
Либо у вас какой-то экзотический "компонент", о котором вы что-то не договариаете.
Re[8]: С# многопоточность
От: Roman039  
Дата: 11.04.12 11:47
Оценка:
Вот! SynhronizationContext — это, похоже, то что я искал. Век живи — век учись.
Большое спасибо.
Re[8]: С# многопоточность
От: Roman039  
Дата: 11.04.12 14:58
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:


HL>Выделенное полужирным можно заменить чем угодно. Это "что угодно" обладает следующими характеристиками:

HL>- оно выполнится в UI-потоке (UI-поток оповещен и выполняет какой-то код);
HL>- пока оно не выполнится, рабочий поток, из которого было сгенерировано событие, будет остановлен (DataArrived будет вызван из рабочего потока, но остановится на context.Send и будет ждать его завершения).

HL>Где вы тут собираетесь использовать два потока и "два экземпляра EventWaitHandler" —

HL>Либо у вас какой-то экзотический "компонент", о котором вы что-то не договариаете.

Подскажите, а такой манёвр (переключение контекста синхронизации) возможен только при использовании UI-потока? Вообщем если инициализировать контекст в форме, то все работает как требуется. А если попробовать реализовать подобную схему с обычными (не UI) классами, то значение SinhronizationContext.Current сбрасывается в null и фактического переключения не происходит. Можно переключать контекст не на UI-поток?
Re[9]: С# многопоточность
От: approach  
Дата: 11.04.12 19:59
Оценка:
Есть хорошее правило из best practice. Основной поток (UI) никогда не нагружать, все операции следует делать в дочерних потоках.
Re[9]: С# многопоточность
От: HowardLovekraft  
Дата: 12.04.12 06:57
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Подскажите, а такой манёвр (переключение контекста синхронизации) возможен только при использовании UI-потока?

Реализации контекста синхронизации из коробки, AFAIK, только для UI (WinForms/WPF/SL).
А как и зачем вы собираетесь использовать контекст синхронизации для не-UI-потоков?

R>Вообщем если инициализировать контекст в форме, то все работает как требуется.

Потому что инфраструктура WinForms инициализирует контекст UI-потока экземпляром WindowsFormsSynchronizationContext.
Re[10]: С# многопоточность
От: Roman039  
Дата: 12.04.12 07:27
Оценка: :)
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Roman039, Вы писали:


R>>Подскажите, а такой манёвр (переключение контекста синхронизации) возможен только при использовании UI-потока?

HL>Реализации контекста синхронизации из коробки, AFAIK, только для UI (WinForms/WPF/SL).
HL>А как и зачем вы собираетесь использовать контекст синхронизации для не-UI-потоков?

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

R>>Вообщем если инициализировать контекст в форме, то все работает как требуется.

HL>Потому что инфраструктура WinForms инициализирует контекст UI-потока экземпляром WindowsFormsSynchronizationContext.
Re: С# многопоточность
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.04.12 16:41
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Вопрос с передачей управления между потоками.


Давай я немножко раскрою термины, чтобы была понятна абсурдность вопроса:

Вопрос с передачей потока управления между потоками управления.


R> Вообщем вопрос: как можно из дополнительного потока передать сигнал в основной поток, так чтобы следующие действия выполнялись именно в основном потоке?


Все зависит от того, что в этот момент делает основной поток. Так что он делает?
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[5]: С# многопоточность
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.04.12 16:49
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Я, читая эту статью, нашел и описание вами предложенного варианта. С Control'ом нельзя: UI не обязательно будет WinForms.


Цикл выборки сообщений будет? Или тоже не обязательно?
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: С# многопоточность
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.04.12 16:49
Оценка:
Здравствуйте, Roman039, Вы писали:

R>Подскажите, а такой манёвр (переключение контекста синхронизации) возможен только при использовании UI-потока?


Нет никакого такого маневра. Тебе опять чего то не то показалось. Контекст синхронизации это всего лишь способ абстрагироваться от конкретного способа синхронизации для конкретного потока.

R> Вообщем если инициализировать контекст в форме, то все работает как требуется.


Его вообще обычно никто явно не инициализирует.

R> А если попробовать реализовать подобную схему с обычными (не UI) классами, то значение SinhronizationContext.Current сбрасывается в null и фактического переключения не происходит.


Инициализация SyncContext происходит неявно. В частности, в случае WinForms, это делается в конструкторе базового класса Control. Т.е. при создании любого элемента управления контекст инициализируется. Чтобы не заморачиваться, использовать следует класс AsyncOperationManager, а не контекст напрямую. И да, если цикла выборки сообщений в потоке нет, то отработка, естественно, будет происходить в потоке вызвавшем (или в отдельном, если испольтзовать Post).
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[10]: С# многопоточность
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.04.12 16:53
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Реализации контекста синхронизации из коробки, AFAIK, только для UI (WinForms/WPF/SL).


И для ASP.NET. Но там он почти ничего не делает.

HL>А как и зачем вы собираетесь использовать контекст синхронизации для не-UI-потоков?


Он же написал — передать управление из другого потока в основной
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[11]: С# многопоточность
От: HowardLovekraft  
Дата: 12.04.12 17:42
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Он же написал — передать управление из другого потока в основной

"Нет, все понятно, но шо конкретно?..." (С) И, главное, зачем?
Re[12]: С# многопоточность
От: Roman039  
Дата: 13.04.12 06:32
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, AndrewVK, Вы писали:


AVK>>Он же написал — передать управление из другого потока в основной

HL>"Нет, все понятно, но шо конкретно?..." (С) И, главное, зачем?

Вы помогли мне решить вопрос с передачей управления в UI-поток. Этот вопрос закрыт. Вопрос о передаче управления в любой другой поток возник из любопытства (просто хотел уточнить можно так сделать или нет) и не имеет отношения к решению задачи. Я нашел статью в которой приводится пример переключения контекста без явного указания на UI-поток (т.е. не указано, что однажды создавалось что то вроде Control'а). Естественно в чистом виде этот пример не заработал (потому что SynhronizationContext.Current оставался null'ом). Вот я и хотел уточнить этот момент.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.