Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Немного потокобезопасности


Автор: HAL707 13.8.2009, 17:39
Всем известно, что при попытке обращения к элементам формы из другого потока небезопасно.
Для этого нужно юзать инвок методы формы или контролов.

Но представим себе такую ситуацию. Разработчик пишет какой-то сложный и навороченный класс (назовем его model). У него в этом классе после создания начинают крутится несколько потоков.
У класса есть событие OnModelChange (типа разработчик хочет информировать потребителя класса о том, что в моделе что-то произошло) Событие вызывает какой-то из внутриклассовых потоков.

Ничего не подозревающий программист юзает этот класс в винаппликейшне. Подписывается на событие OnModelChange и в функции-обработчике события пишет что-то типа label1.Text = "Модель стартовала"
Нажимает он значит кнопочку Play в Студии и видит эксепшн, т.к. обработчик события вызвал внутренний поток класса и т.к. там узаются контролы (label1) - это небезопасно. Но прогер то этого не знает, и ему вообще невдомек, что в классе есть отдельные потоки. Ну и начинает он искать причины ошибки, а потом ругать разработчика...

Это все, я думаю, не есть хорошо. Встает вопрос, а можно ли как-то вызвать событие безопасно, но не передавая в класс ни формы, ни контролов (классу вообще параллельно где он используется). Т

Есть мнения по этому поводу?

Автор: Rohoss 13.8.2009, 18:00
Что-то я не совсем понял вас… Разработчик навороченного класса model должен позаботится о синхронизации.

Автор: PashaPash 13.8.2009, 18:17
HAL707, ес-но можно. Например, при создании модели запоминать System.Windows.Threading.Dispatcher для создавшего потока, и оборачивать вызов события в Invoke. 

Автор: HAL707 14.8.2009, 08:55
Rohoss, что то меня последнее время никто не понимает...
PashaPash, можно пример?

Автор: PashaPash 14.8.2009, 13:15
HAL707, 
Код

    class Model
    {
        private Dispatcher Dispatcher { get; set; }

        public Model()
        {
            this.Dispatcher = Dispatcher.CurrentDispatcher;
        }

        public void DoWork()
        {
            ThreadPool.QueueUserWorkItem(Worker);
        }

        public event EventHandler SomeEvent;

        private void OnSomeEvent()
        {
            this.Dispatcher.Invoke(new MethodInvoker(delegate()
                {
                    EventHandler handler = this.SomeEvent;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                }));
        }

        void Worker(object state)
        {
            Thread.Sleep(3000);
            OnSomeEvent();
        }
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Model m = new Model();
            m.SomeEvent +=new EventHandler(m_SomeEvent);
            
            m.DoWork();
        }

        void  m_SomeEvent(object sender, EventArgs e)
        {
            this.label1.Text = "Hello, World!";
        }
    }


Автор: HAL707 18.8.2009, 10:41
Спасибо, то что нужно  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)