Возникла такая проблема. Время от времени, BackgroundWorker.RunWorkerCompleted вызывается не из потока, который создал объект (как должно быть), а из других потоков.
Тестовый код такой:
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
var worker = new BackgroundWorker();
worker.DoWork += (s, args) => Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
worker.RunWorkerCompleted += (s, args) => Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
worker.RunWorkerAsync();
Выдает например такую фигню: 10 6 11
(должно быть 10 6 10)
Причина в том, что BackgroundWorker.RunWorkerCompleted не должен вызывается из потока, который создал объект.
Он должен вызываться с тем же контекстом синхронизации, в котором работал поток, создавший объект. Если контекст синхронизации есть, то эти два высказывания эквивалентны. А вот если контекста синхронизации нет, то BackgroundWorker.RunWorkerCompleted вызывается из потока из пула.
Здравствуйте, rumatavz, Вы писали:
R>Он должен вызываться с тем же контекстом синхронизации, в котором работал поток, создавший объект. Если контекст синхронизации есть, то эти два высказывания эквивалентны. А вот если контекста синхронизации нет
Здравствуйте, user485, Вы писали:
U>Здравствуйте, rumatavz, Вы писали:
R>>Он должен вызываться с тем же контекстом синхронизации, в котором работал поток, создавший объект. Если контекст синхронизации есть, то эти два высказывания эквивалентны. А вот если контекста синхронизации нет
U>А где и как он устанавливается?
У вас есть поток, который исполняет некий код, в этом потоке вы создаете воркера, и хотите чтоб по завершению работы один из методов воркера выполнился в исходном потоке. Проблема в том, что в вашем потоке продолжает исполнятся какой то другой код. То есть по сути дела метод воркера должен как бы вклинится в исполняющийся в потоке код в случайном месте. Это не возможно. А если бы и было возможно, то было бы ничем не лучше, чем если бы этот метод выполнился в другом потоке.
С гуевым потоком совсем другая история. В гуёвом потоке есть цикл обработки сообщений, и если мы хотим выполнить метод в этом потоке, то просто добавляем сообщение в очередь. В какой то момент оно обработается. При его обработке будет вызван тот метод, который требовалось. Здесь не требуется никакого вклинивания в случайный момент времени.
Расскажите плз, какую задачу вы решаете, т.к. наиболее вероятно, что здесь вообще не нужен BackgroundWorker.
Здравствуйте, rumatavz, Вы писали:
R>У вас есть поток, который исполняет некий код, в этом потоке вы создаете воркера, и хотите чтоб по завершению работы один из методов воркера выполнился в исходном потоке. Проблема в том, что в вашем потоке продолжает исполнятся какой то другой код. То есть по сути дела метод воркера должен как бы вклинится в исполняющийся в потоке код в случайном месте. Это не возможно. А если бы и было возможно, то было бы ничем не лучше, чем если бы этот метод выполнился в другом потоке.
R>С гуевым потоком совсем другая история. В гуёвом потоке есть цикл обработки сообщений, и если мы хотим выполнить метод в этом потоке, то просто добавляем сообщение в очередь. В какой то момент оно обработается. При его обработке будет вызван тот метод, который требовалось. Здесь не требуется никакого вклинивания в случайный момент времени.
Мимо. Основной поток, который создает воркера — GUI, никакими долгими задачами он не занят.
R>Расскажите плз, какую задачу вы решаете, т.к. наиболее вероятно, что здесь вообще не нужен BackgroundWorker.
Нужно выполнить большой и сложный код, который включает вычисления и обращения к сети.
Здравствуйте, user485, Вы писали:
R>>Расскажите плз, какую задачу вы решаете, т.к. наиболее вероятно, что здесь вообще не нужен BackgroundWorker.
U>Нужно выполнить большой и сложный код, который включает вычисления и обращения к сети.
BackgroundWorker и Control.Invoke() спасет отца демократии. И все равно из какого потока пойдет сообщение.