Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.72/25: Рейтинг темы: голосов - 25, средняя оценка - 4.72
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
1

Передача функции в главный поток в консольном приложении

16.09.2017, 05:02. Показов 4624. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте! Посмотрите пожалуйста свежим взглядом на проблему, ибо я, похоже, зациклился на одном варианте, и не вижу решения. Ну, или как обычно туплю в очевидных для всех вещах... =_=
Суть проблемы, если упростить всю систему, вот в чём. Есть консольное приложение, в нём есть поток, который выполняет определённое действие и завершается, и, по результатам его работы, мне нужно запустить определённую функцию, которая должна работать уже в основном потоке. В приложениях WindowsForms я решал такую проблему методом вызова BeginInvoke, для основной формы, а тут я немножко подзавис.
Заранее спасибо за советы.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.09.2017, 05:02
Ответы с готовыми решениями:

Передача объекта обратно в главный поток из другого потока
Добрый день. У меня ест фрагмент в котором я запускаю новый поток, после этого я хочу вернуть...

Получение значения из фонового потока и передача его в главный поток
как получить значение из фонового потока и передать его в главный поток?Знаю что метод должен быть...

Построение графика функции в консольном приложении
Здравствуйте! Пишу в Visual Studio 2013. Консольное приложение. Хочу построить график функции. Как...

Код который работает в консольном приложении в приложении Windows Forms выдает ошибку
Есть код для записи видео с экрана. В консольном приложении он работает, записывает все как нужно....

20
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 07:36 2
Для таких вещей предусмотрен механизм событий.
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 07:51  [ТС] 3
IamRain, Эммм... Может я что-то путаю, но я пробовал реализовать это с событием, и функция, вызванная им всё-равно шла во вторичном потоке, а не в основном (Сорри, за кривой код, он из моего тестового оконного приложения, в котором я ковыряю эту проблему):
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    public partial class Form1 : Form
    {
 
        aaa Counter = new aaa();
        Handler_I Handler1 = new Handler_I();
 
 
        public Form1()
        {
            InitializeComponent();
 
            //Подписались на событие
            Counter.onCount += Handler1.ddd;
        }               
 
 
        private void button2_Click(object sender, EventArgs e)
        {            
            Counter.ccc1();
        }
 
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Add(Counter.ff());       
        }
    }
 
    class Handler_I 
    {
        public void ddd()
        {
            while (true) ;
        }
    }
 
    class aaa  
    {
        Thread th;
 
        public aaa()
        {
            th = new Thread(new ThreadStart(ccc));
        }
 
 
 
        public delegate void MethodContainer();
 
        //Событие OnCount c типом делегата MethodContainer.
        public event MethodContainer onCount;
 
        public void ccc()
        {
            onCount();
        }
 
        public void ccc1()
        {
            th.Start();
        }
 
 
        public string ff()
        {
            return th.ThreadState.ToString();
        }
 
    }

При выводе в листбокс, информации о цикле, после его запуска, он показывает что цикл работает, хотя по идее, цикл должен был завершиться и функция ddd(); должна была выполниться в основном потоке.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 08:06 4
Вот такой пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Program
    {
        static void Main(string[] args)
        {
           
            var runner = new JobRunner();
            runner.JobDone += (s, e) =>
            {
                Console.WriteLine($"EventHandler thread: {Thread.CurrentThread.ManagedThreadId}");
                Console.WriteLine($"Completed successfully: {e.IsSuccessful}");
            };
            runner.DoJobInThreadPoolThread();
            Console.ReadKey(true);
        }
    }
 
 
 
 
    public class JobRunner
    {
        public event EventHandler<JobRunnerEventArgs> JobDone;
 
 
        public void DoJobInThreadPoolThread()
        {
            Task.Run(async() =>
            {
                Console.WriteLine($"PoolThread threadId: {Thread.CurrentThread.ManagedThreadId}");
                for (int i = 0; i < 5; i++)
                {
                    await Task.Delay(800);
                    Console.WriteLine($"Iteratoion: {i}");
                }
                JobDone?.Invoke(this, new JobRunnerEventArgs(true));
            });
        }
    }
 
 
    public class JobRunnerEventArgs : EventArgs
    {
        public JobRunnerEventArgs(bool isSuccessful)
        {
            IsSuccessful = isSuccessful;
        }
 
        public bool IsSuccessful { get; }
    }
У меня чаще всего выдает ожидаемый результат:
Миниатюры
Передача функции в главный поток в консольном приложении  
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 08:21  [ТС] 5
IamRain, хм... Чёт я слегка запутался. Похоже я действительно что-то напутал, пока у себя ковырял код. Спасибо большое, ваш вариант пашет 100%. Буду разбираться.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 08:49 6
Лучший ответ Сообщение было отмечено Захарка как решение

Решение

В приложениях с GUI для вызова методов в потоке GUI используется так называемый SyncronizationContext, а именно
это делает SyncronizationContext.Post method. В который передается делегат, который должен быть вызван.
Control.BeginInvoke внутри себя как раз таки и использует этот SyncronizationContext.Post. В консольных приложениях нет каких-то особо выделяющихся потоков, и поэтому нет надобности в контексте синхронизации, т.е в консоли:

C#
1
var context = SyncronizationContext.Current; // null
Но при надобности можно создать его самостоятельно. Я не достаточно глубоко разбираюсь в этой тематике, но вы можете поразбираться с этими контекстами и возможно, что получится прикрутить подобный функционал и в консоли.
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 09:03  [ТС] 7
IamRain, Кхм... Я ещё раз перепроверил ваш вариант, и чёт нифига... Я попробовал несколько вариантов, но так и так, событие выполняется в потоке созданном в классе.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 09:05 8
Захарка, все же это нерабочее решение, потому что может быть и такой результат:

Вообщем, нужно разбираться с контекстами синхронизации.
Миниатюры
Передача функции в главный поток в консольном приложении  
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 09:07  [ТС] 9
IamRain, это да... Сейчас просились ещё, и на свежую голову буду думать... Спасибо большое, за помощь!
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 09:20 10
Захарка, вам очень важно, чтобы код выполнялся в каком-то конкретном потоке?
Второй пост был написан исходя из того, что я решил вам нужна просто необходимость уведомления о завершении какого-либо действия. Разве важно то, в каком потоке будет происходить обработка результатов работы?
0
1150 / 858 / 263
Регистрация: 30.04.2009
Сообщений: 3,598
16.09.2017, 10:16 11
Чтоб вы понимали... Чудес не бывает, и для того, чтобы можно было выполнить что-то в определенном потоке, в этом потоке просто есть бесконечный цикл, который проверяет наличие "задач", которые ему прислали и в порядке очереди их выполняет.
Реализация в зависимости от технологии (WinForms, WPF и т.д.) отличается, но смысл один и тот же.
А SynchronizationContext - это просто общая абстракция, которая сделана для унификации выполнения тасков.
Написал бы простенькую реализацию для примера, но не вижу смысла так извращаться в консольном приложении.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 10:25 12
Цитата Сообщение от nicolas2008 Посмотреть сообщение
в этом потоке просто есть бесконечный цикл, который проверяет наличие "задач", которые ему прислали и в порядке очереди их выполняет.
Цикл обработки сообщений присутствует только для GUI потоков, поскольку, у них есть свои особые задачи по работе с интерфейсом. Остальным же потокам (worker, io) это ни к чему.
0
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 15:48  [ТС] 13
IamRain, так, я проспался, и могу примерно сформулировать, зачем мне такие. У меня в проекте есть ядро Авесомиума, использующееся в консольном режиме. Все обращения к нему могут выполняться только в main-потоке, но это решаемо средствами самого авесомиума. В итоге получается такая примерно фигня:
1) Класс ожидания действий имеет свой поток.
2) По наступлению определённого момента, он вызывает класс работы с сайтом.
3) У него есть свои потоки, и он шлёт классу работы с браузером Java-запросы на выполнение.
4) Класс работы с браузером выполняет скрипты в main-потоке, и возвращает полученные данные в класс работы с сайтом.
В итоге получается косяк - класс работы с сайтом висит в потоке класса ожидания действий, а класс работы с браузером может вызвать функцию обработки вытянутых данных только для main-потока. А, чтобы всё исправить, нам всего-лишь нужно чтобы класс работы с сайтом сам был в main-потоке. Таким образом, мне нужно вызывать его функции, передав их в мейн поток.
Примерно так.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 16:31 14
То есть авесониум умеет выполнять делегаты в нужных потоках? Если да, то разбирайтесь, как в нем это делается.
John Skeet отвечает:
EDIT: Now that you've made it clear it's a console app, you'll have to work out some form of message pump. Unless a thread is listening for messages somehow, there's no way of forcing it to execute another bit of code. I haven't used the library you've talked about - but if it's forcing you to execute code on a particular thread, then it should provide some equivalent of Control.Invoke etc
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 16:39  [ТС] 15
IamRain, Там сложно. Дело в том, что у авесомиума есть класс WebView, который является оболочкой браузера, и позволяет выполнять скрипты, и делать прочие интересные вещщи. И он имеет метод BeginInvoke, но! Он у меня есть только в классе общения с браузером, и используется только внутри него, так как большую часть времени его не существует. Я, конечно, могу использовать костыльный метод, создав экземпляр класса WebView, в одном из файлов, и написав оболочку, для выполнения, через него обращения к main-потоку, но это как-то печально. Надеялся, что есть адекватный метод решения данной проблемы...
Спасибо вам большое за помощь.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 16:55 16
Ну, на SO есть еще один вроде бы толковый ответ:
In the case of a delegate - a standard producer/consumer queue should work fine (as long as it is thread-safe).
Насколько я понял, можно .net-овскими средствами синхронизации организовать очередь так, чтобы нужный поток получал элемент очереди, к которому можно привязать исполняемый код, который и будет исполнятся в этом потоке. По ссылке можно найти пример реализации очереди.
1
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 16:59  [ТС] 17
IamRain, спасибо большое, буду разбираться.
0
3654 / 2567 / 717
Регистрация: 02.08.2011
Сообщений: 6,928
16.09.2017, 17:07 18
У Stephen-а Cleary имеется два решения.
I think the best solution is to use Task objects and queue them to an StaThreadScheduler running a single thread.
Так, понял, просто оборачивать нужную логику в Task-у и ставить в очередь на выполнение этому StaThreadScheduler-у, который все будет выполнять в одном потоке. Кажется, это наипростейшее решение для вас.
1
138 / 138 / 53
Регистрация: 14.06.2016
Сообщений: 467
16.09.2017, 17:26 19
Цитата Сообщение от nicolas2008 Посмотреть сообщение
и для того, чтобы можно было выполнить что-то в определенном потоке, в этом потоке просто есть бесконечный цикл, который проверяет наличие "задач"
на самом деле это не обязательно, есть и уровень пониже.
0
134 / 129 / 59
Регистрация: 16.06.2013
Сообщений: 523
16.09.2017, 20:04  [ТС] 20
Товарищи! Дико извиняюсь! Я - полный идиот, который никогда не дочитывает до конца >_<. В своё оправдание могу сказать только то, что я весь вечер и ночь над этим ковырялся, и голова совсем не варила в тот момент. Простите, за потраченное время. Авесомиум, при запуске ядра, передаёт контекст синхронизации, для своего потока. Ещё раз сорри =(.
0
16.09.2017, 20:04
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.09.2017, 20:04
Помогаю со студенческими работами здесь

Передача в поток, функции с двумя параметрами
Всем привет, у меня возникла проблема, при создании потока, в него нужно передать функцию с двумя...

Главный поток и вторичный
1. При нажатии на кнопку Start в новом потоке запускается server.AcceptTcpClient() (который...

Дополнительный поток тормозит главный
Всем здравствуйте. Вот код, использующий работу нескольких потоков: Public Class Form1 '...

BackgroundWorker блокирует главный поток
Подскажите как поправить. Код копирует файлы отмеченные галочками в ListView, увеличивает значение...

Приостановить главный поток до закрытия формы
В общем не могу понять, как сделать так, чтоб поток main тормозился, пока не закроется форма ...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru