Проектирование взаимодействия двух потоков (ООП)

Тема в разделе "WASM.HEAP", создана пользователем Green_DiCk, 11 окт 2009.

  1. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    Рассмотрим стандартную ситуацию:

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

    Код (Text):
    1. interface DataWaiter   // Интерфейс ожидания данных
    2. {
    3.      DataReceived();
    4. }
    5.  
    6.  
    7. class MainClass implements DataWaiter
    8. {
    9.  
    10.  
    11.        boolean m_bDaraReceived;
    12.  
    13.        main()
    14.        {    
    15.              m_bDaraReceived = false;
    16.              DataReceiver dr = new DataReceiver();
    17.              dr.loadData(this);
    18.              
    19.              while (!m_bDataReceived)
    20.              {
    21.                    Sleep(1000);
    22.              }
    23.              Data data = dr.getData();
    24.              processData(data);                          
    25.        }
    26.  
    27.        DataReceived()
    28.        {
    29.              m_bDataReceived = true;
    30.        }
    31.  
    32.  
    33.        processData(Data data)
    34.        {
    35.                 // Сложные манипуляции с данными
    36.        }
    37. }
    38.  
    39.  
    40.  
    41. class DataReceiver
    42. {
    43.  
    44.        Data data;
    45.        loadData (DataWaiter observer)
    46.        {
    47.              beginThread
    48.  
    49.                   // Получаем данные из сети
    50.                   data = ...
    51.  
    52.                   observer.DataReceived();
    53.                  
    54.              endThread
    55.        }
    56.  
    57.  
    58.        Data getData() {   return data;   }
    59. }
    Главный поток запрашивает данные и ждёт пока они будут получены. Напрашивается вопрос - а на кой тогда отдельный поток, если главный в это время всё равно простаивает??

    Тогда немного изменим код:

    Код (Text):
    1. interface DataWaiter   // Интерфейс ожидания данных
    2. {
    3.      DataReceived();
    4. }
    5.  
    6.  
    7. class MainClass implements DataWaiter
    8. {
    9.  
    10.        main()
    11.        {    
    12.              m_bDaraReceived = false;
    13.              DataReceiver dr = new DataReceiver();
    14.              dr.loadData(this);    
    15.  
    16.              // Дальше можно заниматься чем угодно.                
    17.        }
    18.  
    19.        DataReceived()
    20.        {
    21.               Data data = dr.getData();      
    22.               processData(data);      // Всё это будет выполняться во вспомогательном потоке!
    23.        }
    24.  
    25.  
    26.        processData(Data data)
    27.        {
    28.                 // Сложные манипуляции с данными
    29.        }
    30. }
    31.  
    32.  
    33.  
    34. class DataReceiver
    35. {
    36.  
    37.        Data data;
    38.        loadData (DataWaiter observer)
    39.        {
    40.              beginThread
    41.  
    42.                   // Получаем данные из сети
    43.                   data = ...
    44.  
    45.                   observer.DataReceived();
    46.                  
    47.              endThread
    48.        }
    49.  
    50.  
    51.        Data getData() {   return data;   }
    52. }
    Вроде бы ничего фатального - все при делах. Но то, что обработка данных тоже будет происходить во вспомогательном потоке меня настораживает, т.к. я подразумевал, что вспомогательный поток будет только загружать данные, а обработка (которая может занимать кучу времени) - это уже не его дело. Иначе получится так, что я не буду знать какой метод в каком потоке у меня выполняется. Часть метододов обработки может вызываться из главного потока, а часть будет вызвана вспомогательным. Это мне не нравится, хотя явных препятствий этому я не вижу.

    PS просьба обсуждать эту проблему так, как она дана, т.е. в асбстрактном плане, не касаясь конкретных механизмов того или иного языка или той или иной программной среды. Например события (Events) в моём случае применить нельзя, поэтому подобные "решения из коробки" неинтересны.
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Какова цель использования потоков?
     
  3. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    почему-то мне видится вместо псевдокода какая-то жаба.
     
  4. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    Booster
    Я затрудняюсь конкретно ответить на этот вопрос. В моей конкретной ситуации возможно и не к чему создавать отдельный поток. Однако есть общее правило, что во избежание зависания основной логики программы и т.д. и т.п. загрузку данных из сети следует выполнять в отдельном потоке.

    n0name
    Так и есть. Я пишу на J2ME и изъясняться мне сейчас проще на джаваподобном наречии. Но это всё таки псевдокод, ибо скомпилировать вышеприведённые кодесы вряд ли удастся.
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Green_DiCk
    Если именно от зависания основной логики, то в простешейшем случае можно крутить её в цикле, совершая полезную работу и проверяя объект синхронизации. А вообще тут никак лучше подходит событийная модель, не обязательно операционной системы, можно её организовать самостоятельно. Некие компоненты которые обрабатывают свои очереди сообщений(аля окна в винде), главный цикл который вызывает методы обработки очередей компонентов(аля ось). Компоненты могут друг другу передавать в очереди сообщения(аля SendMessage).
     
  6. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    Booster
    Пожалуй в этом направлении и буду работать. Эта мысль у меня присутствовала, но по непонятной причине (хотя так часто бывает) я её не рассматривал серьёзно. Спасибо что ткнул меня куда надо. Собственная система событий в любом случае будет полезна, т.к. стандартная модель событий в MIDP очень ограничена.
     
  7. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    Где можно почитать про написание собственного класса Event?

    Или какой-нибудь пример достойный, в котором грамотно реализовано (на любом языке).

    Хочется семь раз изучить, один раз накодить.

    Погуглил, но пока ничего вразумительного. Если есть книжка какая-нибудь, то вообще здорово.
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Green_DiCk

    А чем занят "главный поток", пока ожидаются данные? Что это за приложение?

    Такого правила нет.


    Booster
    Все уже давно придумано.
     
  9. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    жаль не везде эту либу можно заюзать
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    o14189

    А где например нельзя? Буст компилится под тучу компиляторов.
     
  11. Green_DiCk

    Green_DiCk New Member

    Публикаций:
    0
    Регистрация:
    8 июл 2007
    Сообщения:
    338
    _DEN_
    Например в J2ME нельзя :)
     
  12. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    к примеру, если нужно что-то вроде фреймворка с одним и тем же интерфейсом и в kernel mode, и в user mode, то скорее всего придется с 0 писать