Re[5]: блокировка трэда
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 25.02.05 14:04
Оценка: +2
Здравствуйте, Delphi, Вы писали:

D>Здравствуйте, Odi$$ey, Вы писали:


OE>>Здравствуйте, <Аноним>, Вы писали:


А>>>Нет, так не пойдет

А>>>Нужно чтобы это был дочерний процесс

OE>>AfxBeginThread не запускает дочерних процессов


А>>>и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).


OE>>WaitForSingleObject точно также "повешает parent", процессор будет загружен аналогично


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


D>Наверное неправильно вопрос сформулировал, сейчас объясню ситуацию.


D>У нас есть какой то гуи утыканные кнопочками, эдитами и т.д., так вот при нажатии на кнопку должен произойти коннект куда-то, что и делает(Our_Func), естественно это подвешивает наш гуи, до тех пор пока не будет получен ответ от сервера, к которому мы коннектились, и невыполнены все операции(вобщем пока не завершится ф-ция). Чтобы наш гуи не вешался разумно использовать трэды, в этом случаи наш гуи не вешается, и там можно нажимать и вводить чего хочешь. Но в таком случае можно(и нужно) нажать на заветную кнопочку, которая запускает соответственно Our_Func, и с уже имеющимся трэдом создастся еще один, при следующем нажатии еще и т.д. Разумеется нам ненадо делать 300 коннектингов к серверу, и мы создаем очередь, а так как количество клиентов в этой очереди неизвестно это будет список(односвязный или двусвязный — смотря для чего). вот мы и исполняем наш


D>
D>while(<указатель на список> != NULL) {
D>     thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
D>                pVal, 
D>                THREAD_PRIORITY_NORMAL, 
D>                0, 
D>                0, 
D>                NULL);
D> <указатель> = <сделующему элементу>;

D>}
D>


D>Но опять же создастся куча трэдов => куча почти одновременных коннектингов(запусков Our_Func);


D>Нужно же делать следующий запуск ф-ции Our_Func, только когда завершился предыдуший, т.е. по очереди, и чтобы при этом не подвисал гуи интерфейс.


D>P.S. При первом нажатии на кнопочку мы добавляем элемент в очередь и запускаем наш цикл, а при последующих нажатиях идет только добавление в очередь.


D>Надеюсь теперь я лучше раскрыл проблему




В общем основная идея такая (о синхронизации сам подумай или спрашивай если чего не понятно):
Есть thread который всегда ждет eventа а начале работы. При нажатии на кнопку ты заносишь в стек клиентов инфу о нем и ставишь event что есть новый клиент и нужно ео обработать. Thread начинает работу... Когда он заканчивает с очередным пользователем, он смотрит есть еще в стеке (нажал ли еще кто нибуть кнопку пока он обрабатывал текущего), и если есть тутже выполняет цикл для второго и т.д пока стек не пуст. Как только пуст — засыпает до следующего eventa и т.д.....
блокировка трэда
От: Delphi  
Дата: 25.02.05 11:46
Оценка:
Здравствуйте.

Имеется програмка

while(i < MAX) {
   thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
                pVal, 
                THREAD_PRIORITY_NORMAL, 
                0, 
                0, 
                NULL);

i++;
}


Нельзя продолжать цикл пока не завершилась Our_Func, да и трэд thread тоже, только после этого можно переходить к следующему запуску трэда.
Вопрос заключается в том чтобы запускать трэды по очериди(по факту завершения предыдущего), а не параллельно.

P.S. предполагаю что смотреть надо в сторону mutex(пробовал, но ничего дельного не вышло => что-то не так делал

Заранее благодарен.




25.02.05 17:32: Перенесено модератором из 'C/C++' — Павел Кузнецов
Re: блокировка трэда
От: leshi Россия  
Дата: 25.02.05 11:55
Оценка:
Здравствуйте, Delphi, Вы писали:

D>Вопрос заключается в том чтобы запускать трэды по очериди(по факту завершения предыдущего), а не параллельно.

Предлагаю так:
while(i < MAX) {
Our_Func(pVal)
}




Раз уж надо дождаться выполнения, то почему бы не запускать в это же потоке?
Re[2]: блокировка трэда
От: LioLick  
Дата: 25.02.05 12:11
Оценка:
Здравствуйте, leshi, Вы писали:

L>Здравствуйте, Delphi, Вы писали:


D>>Вопрос заключается в том чтобы запускать трэды по очериди(по факту завершения предыдущего), а не параллельно.

L>Предлагаю так:
L>
L>while(i < MAX) {
L>Our_Func(pVal)
L>}
L>


L>


L>Раз уж надо дождаться выполнения, то почему бы не запускать в это же потоке?

Абсолютно согласен, но раз уж человеку хочется:

while(i < MAX) 
{
    thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
                pVal, 
                THREAD_PRIORITY_NORMAL, 
                0, 
                0, 
                NULL);
    ::WaitForSingleObject(thread.m_hThread , INFINITE);
    i++;
}

Ну и разумеется, не забываем проверять код возврата
GL!
Re[2]: блокировка трэда
От: Аноним  
Дата: 25.02.05 12:11
Оценка:
Здравствуйте, leshi, Вы писали:

L>Здравствуйте, Delphi, Вы писали:


D>>Вопрос заключается в том чтобы запускать трэды по очериди(по факту завершения предыдущего), а не параллельно.

L>Предлагаю так:
L>
L>while(i < MAX) {
L>Our_Func(pVal)
L>}
L>


L>


L>Раз уж надо дождаться выполнения, то почему бы не запускать в это же потоке?


Нет, так не пойдет
Нужно чтобы это был дочерний процесс и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).
Если просто запцускать как указано выше, то это будет вешать прогу до момента завершения функции.
Re[3]: блокировка трэда
От: leshi Россия  
Дата: 25.02.05 12:20
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>Раз уж надо дождаться выполнения, то почему бы не запускать в это же потоке?


А>Нет, так не пойдет

А>Нужно чтобы это был дочерний процесс и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).
Имеет смысл, только если процессорное время платное, а паралельный поток запускаешь от чужого имени. А вообще, я еще поспорю, в каком случае меньше нагружается процессор. Мой вариант предполагает вызов функции (call addr), что занимает буквально чуток. Вариант с паралельными потоками предполагает создание нового потока (выделение памяти, занесения в таблицу потоков и т.п., в это я не силен) и кроме того, проверку блокировки потока родителя. А?


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

... а если WaitForSingleObject, то вешать будет до момента завершения процесса.
А если нет разницы, то зачем платить больше?
Re[3]: блокировка трэда
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 25.02.05 12:32
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Нет, так не пойдет

А>Нужно чтобы это был дочерний процесс

AfxBeginThread не запускает дочерних процессов

А>и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).


WaitForSingleObject точно также "повешает parent", процессор будет загружен аналогично

А>Если просто запцускать как указано выше, то это будет вешать прогу до момента завершения функции.
Re[4]: блокировка трэда
От: Delphi  
Дата: 25.02.05 13:23
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, <Аноним>, Вы писали:


А>>Нет, так не пойдет

А>>Нужно чтобы это был дочерний процесс

OE>AfxBeginThread не запускает дочерних процессов


А>>и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).


OE>WaitForSingleObject точно также "повешает parent", процессор будет загружен аналогично


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


Наверное неправильно вопрос сформулировал, сейчас объясню ситуацию.

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

while(<указатель на список> != NULL) {
     thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
                pVal, 
                THREAD_PRIORITY_NORMAL, 
                0, 
                0, 
                NULL);
 <указатель> = <сделующему элементу>;

}


Но опять же создастся куча трэдов => куча почти одновременных коннектингов(запусков Our_Func);

Нужно же делать следующий запуск ф-ции Our_Func, только когда завершился предыдуший, т.е. по очереди, и чтобы при этом не подвисал гуи интерфейс.

P.S. При первом нажатии на кнопочку мы добавляем элемент в очередь и запускаем наш цикл, а при последующих нажатиях идет только добавление в очередь.

Надеюсь теперь я лучше раскрыл проблему
Re[5]: блокировка трэда
От: Alexmoon Украина  
Дата: 25.02.05 13:43
Оценка:
Здравствуйте, Delphi, Вы писали:

D>Здравствуйте, Odi$$ey, Вы писали:


OE>>Здравствуйте, <Аноним>, Вы писали:


[skip]

Если у тебя есть какая то значительная часть GUI которая увешана контролами over long operation, тогда может подумать о пуле потоков. Это раз.
Если операции операции должны выполняться последовательно, то может стоит в начале твоей Our_Func просто заблокировать контрол для активации данного действа, а в конце перед обновлением состояния оболочки твоего приложения раблокировать. А в строке состояния, говорить о процессе выполнения данной операции, иначе о как много непонятных ситуаций может возникнуть.
Так на мой взгляд будет и визуальнее и логичнее.
Если ты все таки так делать не хочешь, то на мой взгляд тебе придется еще реализовать и консоль состяния выполнения, если ты позволишь в очередь вешать сколь угодно операций. При последовательном выполнении я вижу в этом смысл, если эти операции имеют большой объем инициализации входных данных. Вообщем вопросы синхронизации да и только. В таких финтах, как мне кажется наиболее логично именно состоянием контролов дублировать смысл происходящего.
Re: блокировка трэда
От: mukos СССР  
Дата: 25.02.05 15:34
Оценка:
Здравствуйте, Delphi, Вы писали:

D>Здравствуйте.


D>Имеется програмка


D>
D>while(i < MAX) {
D>   thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
D>                pVal, 
D>                THREAD_PRIORITY_NORMAL, 
D>                0, 
D>                0, 
D>                NULL);

D>i++;
D>}
D>


D>Нельзя продолжать цикл пока не завершилась Our_Func, да и трэд thread тоже, только после этого можно переходить к следующему запуску трэда.


Отчегоже?

D>Вопрос заключается в том чтобы запускать трэды по очериди(по факту завершения предыдущего), а не параллельно.


А зачем тебе тогда треды?

D>P.S. предполагаю что смотреть надо в сторону mutex(пробовал, но ничего дельного не вышло => что-то не так делал


D>Заранее благодарен.
Re[5]: блокировка трэда
От: McQwerty Россия  
Дата: 25.02.05 17:29
Оценка:
Здравствуйте, Delphi, Вы писали:

D>Здравствуйте, Odi$$ey, Вы писали:


OE>>Здравствуйте, <Аноним>, Вы писали:


А>>>Нет, так не пойдет

А>>>Нужно чтобы это был дочерний процесс
OE>>AfxBeginThread не запускает дочерних процессов
А>>>и не вешал parent...дожидаться нужно без затрат процессорного времени(может WaitForSingleObject ?).
OE>>WaitForSingleObject точно также "повешает parent", процессор будет загружен аналогично
А>>>Если просто запцускать как указано выше, то это будет вешать прогу до момента завершения функции.
D>Наверное неправильно вопрос сформулировал, сейчас объясню ситуацию.

D>У нас есть какой то гуи утыканные кнопочками, эдитами и т.д., так вот при нажатии на кнопку должен произойти коннект куда-то, что и делает(Our_Func), естественно это подвешивает наш гуи, до тех пор пока не будет получен ответ от сервера, к которому мы коннектились, и невыполнены все операции(вобщем пока не завершится ф-ция). Чтобы наш гуи не вешался разумно использовать трэды, в этом случаи наш гуи не вешается, и там можно нажимать и вводить чего хочешь. Но в таком случае можно(и нужно) нажать на заветную кнопочку, которая запускает соответственно Our_Func, и с уже имеющимся трэдом создастся еще один, при следующем нажатии еще и т.д. Разумеется нам ненадо делать 300 коннектингов к серверу, и мы создаем очередь, а так как количество клиентов в этой очереди неизвестно это будет список(односвязный или двусвязный — смотря для чего). вот мы и исполняем наш


D>P.S. При первом нажатии на кнопочку мы добавляем элемент в очередь и запускаем наш цикл, а при последующих нажатиях идет только добавление в очередь.


D>Надеюсь теперь я лучше раскрыл проблему


Я бы сделал так: при старте программы сразу создал-бы поток.
Сбоку присобачил-бы очередь запросов. И событие, что очередь поменялась.

Порождённый поток ожидает события, просыпается, извлекает из очереди
первый запрос, обрабатывает, если очередь пуста — опять спит.

ГУЙ-поток при нажатии кнопки формирует запрос, помещает его в очередь,
поднимает событие и работает дальше.

При завершении работы ГУЙ-потока ставим в очредь спец-запрос: "кончай".
По этому запросу дополнительный поток завершается.

Очередь запросов, конечно, нужно делать потоко-безопасной. Но это мелочи.
Re[6]: блокировка трэда
От: Alexmoon Украина  
Дата: 26.02.05 07:03
Оценка:
Здравствуйте, McQwerty, Вы писали:

идея, да. но маленькие уточнения: я бы сделал так.

1. Объект назвал бы PostEventHandler.

Я бы сделал так: при старте программы сразу создал-бы поток.
Сбоку присобачил-бы очередь запросов. И событие, что очередь поменялась.

Все эти вещи по отдельности несут в себе не логичный смысл.

2. Закрытые члены PostEventHandler:
— дескриптор события;
— дескриптор потока.
3. Функцию потока я бы сделал статическим методом этого класса.
В конструкторе создавал бы объект событие и новый поток с использованием соответсвующих дескрипторов.
Событие естественно с ручным сбросом.
В деструкторе все уничтожал бы.
4. Указатель на экземпляр соответстсвующего типа передавал бы через механизм user data.
5. Очередь запросов естественно была бы закрытым членом PostEventHandler.

Порождённый поток ожидает события, просыпается, извлекает из очереди
первый запрос, обрабатывает, если очередь пуста — опять спит.

6. Инкапсулировал бы интерфейс добавления элементов в очередь и извлечения их оттуда.

Очередь запросов, конечно, нужно делать потоко-безопасной. Но это мелочи.

7. Отдельную конечную операцию работы с внутренним контейнером обрамил бы критической секцией.
8. В начале потока ожидание события, и затем работа над очередным запросом.

ГУЙ-поток при нажатии кнопки формирует запрос, помещает его в очередь,
поднимает событие и работает дальше.

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

При завершении работы ГУЙ-потока ставим в очредь спец-запрос: "кончай".
По этому запросу дополнительный поток завершается.

11.В деструкторе полное сворачивание всех внутренних ресурсов.
12. Счетчик элементов естественно собственностью очереди.

В первом приближении вроде все. Схема на первый взгляд логична, а остальные тонкости по месту отточил бы.
Re[7]: блокировка трэда
От: Delphi  
Дата: 27.02.05 09:10
Оценка:
Здравствуйте, Alexmoon, Вы писали:


A>9. В методе добавления элемента в список, в самом конце выставление события в сигнальное состояние.

A>10.В методе извлечения в конце с проверкой очереди на пустоту сбрасывание, если элементов нет.

Предположим, что кол-во элементов нам известно(для упрощения схемы). Пусть их будет, например, 5. =>

.........
HANDLE hEvent; // глобальная переменная, так же как и thread;
.........
i = 0;
while (i < 5) {
     hEvent = CreateEvent(NULL, false, false, "asda");

     thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
                element[i], 
                THREAD_PRIORITY_NORMAL, 
                0, 
                0, 
                NULL);
     SetEvent(hEvent); // выставляем событие в сигнальное состояние, чтобы Our_Func запустилась 
     ResetEvent(hEvent); // сбрасываем событие
i++;

}
.............

...Our_func..() 
{
     WaitForSingleObject(hEvent,INFINITE); // ожидаем сигнала
     ................
     
     ................
     SetEvent(hEvent);
     return true;
}


Так вот, если у нас всего 2 элемента, то все хорошо, однако при большем количестве накапливается куча ожидающих своего часа событий, и как только 1-й завершившийся трэд делает SetEvent(hEvent), они все дружно просыпаются...., можно конечно в цикл запихать WaitForSingleObject(hEvent,INFINITE), но тогда смысл трэдов теряется.
Да и с SetEvent(hEvent) внутри цикла нужно что-то делать, т.к. это неправильно, да и по логике работать не должно
Re[8]: блокировка трэда
От: Alexmoon Украина  
Дата: 28.02.05 08:15
Оценка:
Здравствуйте, Delphi, Вы писали:

D>Здравствуйте, Alexmoon, Вы писали:



A>>9. В методе добавления элемента в список, в самом конце выставление события в сигнальное состояние.

A>>10.В методе извлечения в конце с проверкой очереди на пустоту сбрасывание, если элементов нет.

D>Предположим, что кол-во элементов нам известно(для упрощения схемы). Пусть их будет, например, 5. =>


D>
D>.........
D>HANDLE hEvent; // глобальная переменная, так же как и thread;
D>.........
D>i = 0;
D>while (i < 5) {
D>     hEvent = CreateEvent(NULL, false, false, "asda");

D>     thread = AfxBeginThread((AFX_THREADPROC)  Our_Func, 
D>                element[i], 
D>                THREAD_PRIORITY_NORMAL, 
D>                0, 
D>                0, 
D>                NULL);
D>     SetEvent(hEvent); // выставляем событие в сигнальное состояние, чтобы Our_Func запустилась 
D>     ResetEvent(hEvent); // сбрасываем событие
D>i++;

D>}
D>.............

D>...Our_func..() 
D>{
D>     WaitForSingleObject(hEvent,INFINITE); // ожидаем сигнала
D>     ................
     
D>     ................
D>     SetEvent(hEvent);
D>     return true;
D>}

D>


D>Так вот, если у нас всего 2 элемента, то все хорошо, однако при большем количестве накапливается куча ожидающих своего часа событий, и как только 1-й завершившийся трэд делает SetEvent(hEvent), они все дружно просыпаются...., можно конечно в цикл запихать WaitForSingleObject(hEvent,INFINITE), но тогда смысл трэдов теряется.

D>Да и с SetEvent(hEvent) внутри цикла нужно что-то делать, т.к. это неправильно, да и по логике работать не должно

Предположим, что кол-во элементов нам известно(для упрощения схемы). Пусть их будет, например, 5. =>

как это облегчает суть решения задачи?

хорошо. обо всем по порядку.

1. О каком SetEvent идет речь внутри рабочего цикла ожидания. Это принципиально неправильно и об это даже речи не шло.
2. SetEvent должен быть только за методом AddEventHandler в реализации объекта PostEventHandler и то я там не уточнил, что его нужно делать в конце метода, после добавления нового элемента с проверкой количества элементов равным 1. Но это легко укладывается в раздел уточнения по ходу реализации.
3. Суть работы механизма — это изоляция работы механизма GUI и его реализации. Если у тебя все обработчики должны работать последовательно, то накой тебе заготовки под все потоки, где смысл в расходе памяти под структуры потока. Как сказал один умный человек они тоже не воздушные. В этом есть смысл только при условии, что хоть часть работы будет выполняться параллельно, да и для этого вполне подходит потоков. Особенности синхронизации при этом ложаться на плечи обработчиков под каждый поток в пуле.
4. Привеленные выше мои слова неужели намекают на подобную реализацию?

...Our_func..() 
{
     WaitForSingleObject(hEvent,INFINITE); // ожидаем сигнала
     ................
     
     ................
     SetEvent(hEvent);
     return true;
}

5. Теперь по цитатам.

Разумеется нам ненадо делать 300 коннектингов к серверу, и мы создаем очередь

зачем в данном случае пул. смысла не вижу. обычный ожидающий цикл в отдельном потоке с толковой синхронизацией это максимум.
даже, если тебе понадобиться при каких то условиях делать отдельный параллельный поток, то в методе добавления обработчика в очередь никто не мешает при условии бросить в пул отдельный парралельный поток.

функцию потока придется наверное привести
...Our_func..() 
{
     while(true)
     {
          if(WaitForSingleObject(hEventExit, 0)    != WAIT_TIMEOUT)  break;
          if(WaitForSingleObject(hEvent, INFINITE) != WAIT_OBJECT_0) break;
          HPARAM _param = GetEvent();
          ................
     }
     CloseHandle(hEventExit);
     CloseHandle(hEvent);
     return 0;
}
AddEvent(const HPARAM& param)
{
     queue_ref.push_back(param);
     if(queue.size == 1) SetEvent(hEvent);
}
HPARAM GetEvent()
{ 
     HPARAM _param = queue.pop();
     if(queue_ref.size == 0) ResetEvent(hEvent);
}
~destructor()
{
    SetEvent(hEventExit);
}


abstract idea.
писал на колене, по этому на синтаксис внимания не обращай.
так как это обработка GUI то я не вижу смысла даже в критической секции.
Но опять же по необходимости, можна дописать все что угодно.
Re[9]: блокировка трэда
От: Alexmoon Украина  
Дата: 28.02.05 08:20
Оценка:
Здравствуйте, Alexmoon, Вы писали:

[skip]

конечно же в функцию потока в при его создании через механизм user data необходимо передавать (LPVOID)this, если конечно енеобходим доступ к внутренним полям.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.