С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10

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

21.01.2014, 13:21. Показов 2738. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
доброго времени суток.
изначально была функция, которая выглядит примерно вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public MyModel[] ReturnList( int id )
{
        MyModel [] ReturnModel = new MyModel[0];
        
        try
        {
               ReturnModel = GetList(id);
        }
        catch
        {
               ReturnModel = null;
        }
  
         return ReturnModel;
}
необходимо преобразовать данный код так, чтобы эта функция вызывалась в отдельном потоке. т.к. у подобных функций есть ограничение, мол, в потоке могут вызываться функции только типа void, то сказали использовать event и delegate.
т.е. начало должно быть такое:
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
public int _id = new int();
 
public void ReturnList( int id )
{
    _id = id;
     Thread TR = new Thread(Tr_ReturnList);
    TR.Start();
}
 
public delegate void MyDelegate ( MyModel []data );
public event MyDelegate MyEvent;
 
public void Tr_ReturnList()
{
     MyModel [] ReturnModel = new MyModel[0];
        
        try
        {
               ReturnModel = GetList(id);
        }
        catch
        {
               ReturnModel = null;
        }
}
не могу понять, что делать дальше. особенно интересует вопрос, как именно возвращать требуемый список.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
21.01.2014, 13:21
Ответы с готовыми решениями:

Сделать так, чтобы при каждом изменении переменной pos вызывалась некоторая сторонняя функция
Нужно сделать так, чтобы при каждом изменении переменной pos вызывалась некоторая сторонняя функция (если быть точным, процедура прорисовки...

Эвенты и делегаты - в чем разница приведенных кодов
Всем доброго времени суток. :) Евенты и делегаты в принципе моё слабое место в C#, а сейчас стал разбирать проект в качестве примера (не...

Чтобы функция вызывалась только 1 раз
вот, у меня в коде присутствует вызов функции авторизации, надо сделать чтобы функция авторизации только 1 раз запускалась в начале.

14
 Аватар для Kill100
434 / 299 / 82
Регистрация: 11.12.2010
Сообщений: 1,209
21.01.2014, 13:45
Самый простой вариант. Использования делигата
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        static public Int32[] ReturnList(Int32 id)
        {
            return new Int32[id];
        }
 
 
        static void Main(string[] args)
        {
 
            var list = new Int32[0];
            var thread = new Thread(() =>list = ReturnList(10));//создаем поток с анонимным делегатом
            thread.Start();//вызываем поток
            thread.Join();// ждем завершения
            Console.WriteLine(list.Length.ToString());//проверяем что изменился размер
            }
Но если надо что то выполнить по завершения выполнения при этом не морозя основной поток
то нужно еще и событие завершения вешать.
1
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 14:05  [ТС]
В данном варианте основной поток же ждет, пока выполнится ReturnList(Int32 id)?(поправьте, если ошибаюсь)
можно ли сделать так, чтобы эти 2 потока выполнялись параллельно? у меня просто таких функций около 40 шт(которые вызываются последовательно) и программа подвисает в ожидании, пока закончится выполнение дочернего потока.
а хочется, чтобы подобного не было(
0
 Аватар для Kill100
434 / 299 / 82
Регистрация: 11.12.2010
Сообщений: 1,209
21.01.2014, 14:10
А вам важно в каком порядке финишируют данные функции?
Или можно создать 40 потоков, запустить их. И потом просто ждать пока все завершатся? И вывести ответ?
0
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 14:14  [ТС]
финиширую по принципу: раньше запустился, раньше вывел результат.
боюсь, что ожидать, пока закончатся все 40 потоков будет слишком долго и преподаватель не оценит(
0
 Аватар для Kill100
434 / 299 / 82
Регистрация: 11.12.2010
Сообщений: 1,209
21.01.2014, 14:15
ТО есть надо просто вывести куда то результат в текстовое поле допустим как только функция завершит выполнение?
0
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 14:17  [ТС]
да. примерно так.
только не вывести, а вернуть собственно само значение.
вывод у меня используется только для того, чтобы оповестить, мол, 'я закончил'
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
21.01.2014, 15:24
А если использовать delegate, IAsyncResult и BeginInvoke - EndInvoke?
По опыту работы с потоками на VB.NET я помню, что через Thread можно вызвать только процедуры (не возвращающие значения), а вот через делегат-и функции. Библиотека классов одна используется, не думаю, что в C# будет по другому...
0
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 17:27  [ТС]
Цитата Сообщение от insite2012 Посмотреть сообщение
А если использовать delegate, IAsyncResult и BeginInvoke - EndInvoke?
а можно поподробнее? что-то сейчас погуглила и поняла, что для меня это какой-то совсем темный лес(
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
21.01.2014, 19:07
http://msdn.microsoft.com/ru-r... -snippet-1
1
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
21.01.2014, 20:48
Лучший ответ Сообщение было отмечено Casper-SC как решение

Решение

Тут и старые варианты разбираются и новые с async и await



Добавлено через 16 минут
Цитата Сообщение от Ternovnik Посмотреть сообщение
финиширую по принципу: раньше запустился, раньше вывел результат
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Threading;
 
namespace ConsoleApplication1
{
    public delegate T GetDataHandler<T>(int id);
 
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 4; i++)
            {
                LoadData(i);
            }
 
            Console.ReadKey();
        }
 
        public static void LoadData(int id)
        {
            GetDataHandler<Something[]> handler = Database.GetData;
            handler.BeginInvoke(id,
                 asyncResult =>
                 {
                     Something[] data = handler.EndInvoke(asyncResult);
                     Display(data);
                 }, null);
        }
 
        public static void Display(Something[] data)
        {
            foreach (Something something in data)
            {
                Console.WriteLine(something.Name);
            }
        }
    }
 
    public class Something
    {
        public Something(string name)
        {
            Name = name;
        }
        public string Name { get; set; }
    }
 
    public class Database
    {
        private static readonly Random _random = new Random();
        private static readonly object _randomSync = new object();
 
 
        public static Something[] GetData(int id)
        {
            Thread.Sleep(GetRandomValue());
            switch (id)
            {
                case 0:
                    return new Something[]
                               {
                                   new Something("1"), 
                                   new Something("2"), 
                                   new Something("3")
                               };
                case 1:
                    return new Something[]
                               {
                                   new Something("4"), 
                                   new Something("5"), 
                                   new Something("6")
                               };
                case 2:
                    return new Something[]
                               {
                                   new Something("7"), 
                                   new Something("8"), 
                                   new Something("9")
                               };
                case 3:
                    return new Something[]
                               {
                                   new Something("10"), 
                                   new Something("11"), 
                                   new Something("12")
                               };
                default:
                    return null;
            }
        }
 
        private static int GetRandomValue()
        {
            lock (_randomSync)
                return _random.Next(100, 400);
        }
    }
}
2
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 21:50  [ТС]
спасибо большое за предложенные варианты! сейчас буду разбираться)
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
21.01.2014, 22:19
Ах да. В выше приведённом коде далеко не гарантируется именно та очерёдность, с которой потоки запускаются. И реально ли это нужно? Ведь при получении разных объёмов данных могут быть разные задержки, то есть, если 1 поток запустился первым, второй вторым и отработал быстрее первого, чтобы ему вывести результат, нужно подождать пока получит данные первый поток? Смысл?

Добавлено через 1 минуту
Вообще, если бы задача была описана максимально подробно, можно было бы сразу сделать как надо, а так можно написать массу вариантов, как получать данные.
0
 Аватар для Ternovnik
0 / 0 / 0
Регистрация: 21.01.2014
Сообщений: 10
21.01.2014, 22:27  [ТС]
ну я так чувствую, что очередность уже не особо важна(хотя изначально было не так).
довольно долго пыталась решить проблему сама. а сейчас - лишь бы данные вменяемо уже получить.
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
21.01.2014, 22:36
Можно вообще сделать, чтобы после того, как отработают все потоки, программа об этом "узнавала" и могла что-то делать.

Не уверен насколько хорош такой вариант, но можно сделать так. Внутри обработчика события DoWork класса BackgroundWorker вызывать код получающий данные в разных потоках. И внутри же обработчика после вызова всех этих потоков прописать
C#
1
2
            // Ждем окончания работы всех потоков
            Task.WaitAll(threads);
Далее, после завершения работы всех потоков сработает обработчик RunWorkerCompleted (на него нужно подписаться) и там уже что-то делать.

Посмотри ещё этот пример:
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
71
72
73
74
75
76
77
78
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
 
namespace ConsApp_Multithreading_UsingTasks
{
    class Program
    {
        // Блокирующая очередь. Сюда будут добавляться "логины" из ричбокса и отсюда их будут доставать обрабатывающие потоки
        static BlockingCollection<int> queue = new BlockingCollection<int>();
 
        static void Main(string[] args)
        {
            // Создаем шесть потоков, которые будут заниматься логином
            Task[] threads = new Task[6];
            for (int i = 0; i < threads.Length; i++)
            {
                int num = i + 1;
                threads[i] = Task.Factory.StartNew(() => ProcessQueue("Thread " + num));
            }
 
            // Создаем очередь "логинов"
            for (int i = 0; i < 100; i++)
            {
                queue.Add(i);
            }
 
            // Эта строчка заставит все слушающие потоки разблокироваться, когда в очереди не останется элементов.
            // На деле ее надо добавлять при завершении работы приложения - чтобы слушающие потоки не висели бесконечно.
            queue.CompleteAdding();
 
            // Ждем окончания работы всех потоков
            Task.WaitAll(threads);
 
            Console.WriteLine("All threads finished execution");
            Console.ReadLine();
        }
 
        // Добавляет элемент в очередь
        static void Enqueue(int value)
        {
            queue.Add(value);
        }
 
        // Удаляет и возвращает первый элемент в очереди
        static int Dequeue()
        {
            return queue.Take();
        }
 
        // Достает элементы из очереди и обрабатывает их
        static void ProcessQueue(object taskName)
        {
 
            while (true)
            {
                try
                {
                    // Достаем следующий элемент из очереди. Если элементов ноль и свойство очереди IsCompleted = false, поток будет заблокирован пока элементы не появятся.
                    int item = Dequeue();
 
                    // Делаем что нам нужно. В данном случае просто выводим полученный из очереди элемент в консоль. На деле здесь будут обрабатываться логины.
                    Console.WriteLine("{0}: processing {1}.", taskName, item);
 
                    // Допустим, один логин занимает 1 секунду.
                    Thread.Sleep(1000);
                }
                catch (InvalidOperationException)
                {
                    // Обеспечиваем выход из бесконечного цикла при завершении работы приложения
                    Console.WriteLine("{0} has finished working", taskName);
                    return;
                }
            }
        }
    }
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.01.2014, 22:36
Помогаю со студенческими работами здесь

Как сделать так, чтобы в каждой надстройке вызывалась своя форма?
Имеются две надстройки, в каждой есть форма About. Если в любой из них вызвать на показ эту форму (About.Show), то показывается только...

Нужно, чтобы функция f вызывалась, приостановя, то один, то другой поток
Даже не знаю как сказать. Попробую объяснить, нужно чтобы через определенное время вы вызвалась функция. void LUAHook(lua_State*...

Как сделать, чтобы по удержанию кнопки некоторое время вызывалась функция?
Здравствуйте. У меня такой вопрос: как сделать , чтобы по удержанию кнопки вызывалась другая функция (или метод, или вообще что-то...

Как сделать так, чтобы при нажатии на клавишу Enter вызывалась кнопка Button
Имеется два TextBox, два RegularExpressionValidator, два RequiredFieldValidator и кнопка Button Как сделать так, чтобы при нажатии...

Функция-член класса в отдельном потоке
люди я столкнулся со странной проблемой. Мне нужно запустить функцию член класса в отдельном потоке. вот код: #include...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru