Здравствуйте, rcon111, Вы писали:
R>Добрый вечер. R>возникла такая проблема, нужно передать значение переменной из одного потока в другой R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
R>
Здравствуйте, rcon111, Вы писали:
_>>так бы сразу и сказал, надо чётче условия задачи формулировать. тогда переменная timer вобще не нужна, надо просто в цикле "слушать" хендл потока через WaitForSingleObject. причём если цикл у тебя кроме ожидания ничего не делает, можно вобще без него обойтись, достаточно задать INFINITE таймаут.
_>>
_>>HANDLE thread = CreateThread (...);
_>>// условие выхода из цикла
_>>DWORD rc = WaitForSingleObject (thread, 0); // второй параметр - таймаут
_>>if (rc != WAIT_TIMEOUT)
_>> break;
_>>...
_>>
R>сделал так, но пчемуто не получается, событие не происходит((( попробывал еще и через SetEvent тоже ничего...
так какое тебе событие все-таки нужно? если событие для тебя — это просто завершение треда, то тебе не нужно заморачиваться с иветами, достаточно слушать хендл треда, как я выше написал. не надо усложнять себе жизнь, и лучше все-таки почитать какую-нибудь литературу по теме, учиться методом тыка — не лучший способ получения знаний.
DWORD WINAPI NetThread(LPVOID lpParam)
{
.....................
HANDLE tmr = CreateThread(NULL, 0, TMR, 0, 0, 0);
DWORD dw1;
while (....)
{
.......
dw1 = WaitForSingleObject(tmr,0);
if (dw1 == WAIT_OBJECT_0)
{
MessageBox (0, L"thread signaled", L"Ok", 0);
break;
}
else if(dw1 == WAIT_TIMEOUT)
{
// это не ошибка, просто поток ещё не успел завершить выполнение
}
else
{
// а тут что-то случилось
MessageBox(0, L"thread failed", L"Error", 0);
break;
}
}
CloseHandle (tmr);
логика кода немного некорректна, поскольку неясно, что за условие в цикле while, и может ли он прерваться до того как тред завершит работу.
Здравствуйте, FlamingWind, Вы писали:
FW>А разве не и? Насколько я понимаю, нужно использовать и мьютекс (чтобы не было общего доступа, когда один поток — читает, другой — пишет), и violate, дабы компилятор не кешировал переменную в регистре, а всегда получал ее актуальное значение из памяти.
Вызов функции синхронизации сам по себе является барьером для оптимизатора, так что volatile в данном случае не нужен. Он может помочь примерно в такой ситуации:
...
atomic_work_flag = 1;
...
while (atomic_work_flag) {
// some async code
}
...
А в случае
...
work_flag = 1;
...
for (;;) {
some_lock();
local_work_flag = work_flag;
some_unlock();
if (local_work_flag == 0)
break;
// some code
}
...
все будет нормально.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Здравствуйте, rcon111, Вы писали:
R>возникла такая проблема, нужно передать значение переменной из одного потока в другой R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
1. Компилятор не знает, что переменная меняется в другом месте, поэтому имеет право для оптимизации выбросить условие. Здесь поможет volatile.
2. Нити могут работать на разных ядрах с некогерентными кэшами. Здесь поможет memory barrier.
3. Не гарантируется, что доступ к переменной будет атомарным. Здесь нужен либо атомарный тип, либо синхронизация, которя также выполнит роль memory barrier.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Здравствуйте, rcon111, Вы писали:
R>Здравствуйте, ДимДимыч, Вы писали:
ДД>>1. Компилятор не знает, что переменная меняется в другом месте, поэтому имеет право для оптимизации выбросить условие. Здесь поможет volatile. ДД>>2. Нити могут работать на разных ядрах с некогерентными кэшами. Здесь поможет memory barrier. ДД>>3. Не гарантируется, что доступ к переменной будет атомарным. Здесь нужен либо атомарный тип, либо синхронизация, которя также выполнит роль memory barrier.
R>а можно поподробнее для меня темного )))
Судя по тому, что Вы не используете volatile при объявлении переменной разделяемой между потоками, не используете механизмы синхронизации – Вам стоит прочитать литературу, посвященную многопоточному программированию.
Здесь достаточно подробная статья, правда на английском. Тут, здесь и там обсуждают назначение volatile. Здесьпро барьеры памяти и многое другое.
Но наверно лучше Вам начать все же с книг. Привожу перечень, хотя есть подозрение, что для начинающего они не очень подходят:
1) Maurice Herlihy — The Art Of Multiprocessor Programming;
2) David R. Butenhof — Programming with POSIX threads;
3) Грегори Р.Эндрюс — Основы многопоточного, параллельного и распределенного программирования.
Добрый вечер.
возникла такая проблема, нужно передать значение переменной из одного потока в другой
как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
обьявляем переменную
BOOL timer;
дочерний поток
DWORD WINAPI TMR(LPVOID lpParam)
{
.....
timer = 0;
}
основной поток из которого родился дочерний
DWORD WINAPI NetThread(LPVOID lpParam)
{
......
CreateThread(NULL, 0, TMR, 0, 0, 0);
.......
далее в одном из циклов ожидаем прихода timer = 0
if(timer == 0)
.... //// так вот это событие и не случается (((
}
Проверьте что возвращает CreateThread, может поток вообще не запускается. Либо проверка флага выполняется до того как он устанавливается в другом потоке. Либо поток TMR не доходит до строчки установки флага. Вариантов много, тут лучше всего поможет отладчик
Здравствуйте, rcon111, Вы писали:
R>Добрый вечер. R>возникла такая проблема, нужно передать значение переменной из одного потока в другой R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
при программировании многопоточных приложений надо учитывать кучу нюансов, таких как синхронизация, разделение ресурсов, доступ к общим данным и т.п. не имея хотя бы общего представления об этих вещах, лучше за многопоточность не браться, если только целью не является самообразование.
в простейшем случае (переменная timer меняет своё значение только внутри функции TMR) можно поступить так:
обьявляем переменную
BOOL timer;
HANDLE events[2];
дочерний поток
DWORD WINAPI TMR(LPVOID lpParam)
{
.....
timer = 0;
SetEvent (events[0]);
}
основной поток из которого родился дочерний
DWORD WINAPI NetThread(LPVOID lpParam)
{
......
events[0] = CreateEvent (NULL, 0, 0, NULL);
events[1] = CreateThread(NULL, 0, TMR, 0, 0, 0);
.......
далее в одном из циклов ожидаем прихода timer = 0
DWORD rc = WaitForMultipleObjects (2, events, 0, 0); // 4-й параметр - таймаут
// если задать таймаут INFINITE, будем ждать до победного конца одного из двух событий:
// либо нам засигналят ивент, либо TMR завершит своё выполнениеif (rc == WAIT_OBJECT_0)
{
// timer == 0
}
else if (rc == WAIT_TIMEOUT)
{
// вышли по таймауту
}
else
{
// случилась херня и нить завершилась не успев поменять переменную timer
}
если содержимое timer может менять не только TMR, то это всё усложняет и тремя строчками уже не обойтись.
Здравствуйте, abdab, Вы писали:
A>Здравствуйте, rcon111, Вы писали:
A>Проверьте что возвращает CreateThread, может поток вообще не запускается. Либо проверка флага выполняется до того как он устанавливается в другом потоке. Либо поток TMR не доходит до строчки установки флага. Вариантов много, тут лучше всего поможет отладчик
CreateThread возвращает 1, поток работает проверял, проверка флага проходит в цыкле while.... вот по этому и не понимаю в чем проблема(
Здравствуйте, ДимДимыч, Вы писали:
ДД>1. Компилятор не знает, что переменная меняется в другом месте, поэтому имеет право для оптимизации выбросить условие. Здесь поможет volatile. ДД>2. Нити могут работать на разных ядрах с некогерентными кэшами. Здесь поможет memory barrier. ДД>3. Не гарантируется, что доступ к переменной будет атомарным. Здесь нужен либо атомарный тип, либо синхронизация, которя также выполнит роль memory barrier.
Здравствуйте, const_volatile, Вы писали:
_>Здравствуйте, rcon111, Вы писали:
R>>Добрый вечер. R>>возникла такая проблема, нужно передать значение переменной из одного потока в другой R>>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
_>при программировании многопоточных приложений надо учитывать кучу нюансов, таких как синхронизация, разделение ресурсов, доступ к общим данным и т.п. не имея хотя бы общего представления об этих вещах, лучше за многопоточность не браться, если только целью не является самообразование.
_>в простейшем случае (переменная timer меняет своё значение только внутри функции TMR) можно поступить так:
_>
_>обьявляем переменную
_>BOOL timer;
_>HANDLE events[2];
_>дочерний поток
_>DWORD WINAPI TMR(LPVOID lpParam)
_>{
_>.....
_>timer = 0;
_>SetEvent (events[0]);
_>}
_>основной поток из которого родился дочерний
_>DWORD WINAPI NetThread(LPVOID lpParam)
_>{
_>......
_>events[0] = CreateEvent (NULL, 0, 0, NULL);
_>events[1] = CreateThread(NULL, 0, TMR, 0, 0, 0);
_>.......
_>далее в одном из циклов ожидаем прихода timer = 0
_>DWORD rc = WaitForMultipleObjects (2, events, 0, 0); // 4-й параметр - таймаут
_>// если задать таймаут INFINITE, будем ждать до победного конца одного из двух событий:
_>// либо нам засигналят ивент, либо TMR завершит своё выполнение
_>if (rc == WAIT_OBJECT_0)
_>{
_> // timer == 0
_>}
_>else if (rc == WAIT_TIMEOUT)
_>{
_> // вышли по таймауту
_>}
_>else
_>{
_> // случилась херня и нить завершилась не успев поменять переменную timer
_>}
_>
_>если содержимое timer может менять не только TMR, то это всё усложняет и тремя строчками уже не обойтись.
если честно, не совсем понял смысл всего этого ((( совсем я темный)
if(timer == 0) находится внутри цыкла while и мне нужно выйти из него когда завершится тот поток.
Поток в С++ представляется в виде статической функции (по умолчанию у процесса есть главный поток представленный методом main).
Создавая поток, вы передаете указатель на статическую функцию, которая будет обработчиком потока, по завершению которой поток завершается...
В эту функцию в качестве параметра можно передать любой блок памяти (в частности указатель на класс)... Остается только синхронизовать обращение к этому общему блоку памяти (или части) из разных потоков... для этого есть мьютерсы или violate...
Здравствуйте, rcon111, Вы писали:
R>если честно, не совсем понял смысл всего этого ((( совсем я темный) R>if(timer == 0) находится внутри цыкла while и мне нужно выйти из него когда завершится тот поток.
так бы сразу и сказал, надо чётче условия задачи формулировать. тогда переменная timer вобще не нужна, надо просто в цикле "слушать" хендл потока через WaitForSingleObject. причём если цикл у тебя кроме ожидания ничего не делает, можно вобще без него обойтись, достаточно задать INFINITE таймаут.
HANDLE thread = CreateThread (...);
// условие выхода из цикла
DWORD rc = WaitForSingleObject (thread, 0); // второй параметр - таймаутif (rc != WAIT_TIMEOUT)
break;
...
Здравствуйте, const_volatile, Вы писали:
_>так бы сразу и сказал, надо чётче условия задачи формулировать. тогда переменная timer вобще не нужна, надо просто в цикле "слушать" хендл потока через WaitForSingleObject. причём если цикл у тебя кроме ожидания ничего не делает, можно вобще без него обойтись, достаточно задать INFINITE таймаут.
_>
_>HANDLE thread = CreateThread (...);
_>// условие выхода из цикла
_>DWORD rc = WaitForSingleObject (thread, 0); // второй параметр - таймаут
_>if (rc != WAIT_TIMEOUT)
_> break;
_>...
_>
сделал так, но пчемуто не получается, событие не происходит((( попробывал еще и через SetEvent тоже ничего...
Здравствуйте, Uzumaki Naruto, Вы писали:
UN>Поток в С++ представляется в виде статической функции (по умолчанию у процесса есть главный поток представленный методом main). UN>Создавая поток, вы передаете указатель на статическую функцию, которая будет обработчиком потока, по завершению которой поток завершается... UN>В эту функцию в качестве параметра можно передать любой блок памяти (в частности указатель на класс)... Остается только синхронизовать обращение к этому общему блоку памяти (или части) из разных потоков... для этого есть мьютерсы или violate...
Здравствуйте, rcon111, Вы писали:
R>Добрый вечер. R>возникла такая проблема, нужно передать значение переменной из одного потока в другой R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...
R>
R>обьявляем переменную
R>BOOL timer;
R>дочерний поток
R>DWORD WINAPI TMR(LPVOID lpParam)
R>{
R>.....
R>timer = 0;
R>}
R>основной поток из которого родился дочерний
R>DWORD WINAPI NetThread(LPVOID lpParam)
R>{
R>......
R>CreateThread(NULL, 0, TMR, 0, 0, 0);
R>.......
R>далее в одном из циклов ожидаем прихода timer = 0
R>if(timer == 0)
R> .... //// так вот это событие и не случается (((
R>}
R>
Здравствуйте, Uzumaki Naruto, Вы писали:
UN>для этого есть мьютерсы или violate...
А разве не и? Насколько я понимаю, нужно использовать и мьютекс (чтобы не было общего доступа, когда один поток — читает, другой — пишет), и violate, дабы компилятор не кешировал переменную в регистре, а всегда получал ее актуальное значение из памяти.
_>DWORD WINAPI NetThread(LPVOID lpParam)
_>{
_>.....................
_> HANDLE tmr = CreateThread(NULL, 0, TMR, 0, 0, 0);
_> DWORD dw1;
_> while (....)
_> {
_> .......
_> dw1 = WaitForSingleObject(tmr,0);
_> if (dw1 == WAIT_OBJECT_0)
_> {
_> MessageBox (0, L"thread signaled", L"Ok", 0);
_> break;
_> }
_> else if(dw1 == WAIT_TIMEOUT)
_> {
_> // это не ошибка, просто поток ещё не успел завершить выполнение
_> }
_> else
_> {
_> // а тут что-то случилось
_> MessageBox(0, L"thread failed", L"Error", 0);
_> break;
_> }
_> }
_> CloseHandle (tmr);
_>
_>логика кода немного некорректна, поскольку неясно, что за условие в цикле while, и может ли он прерваться до того как тред завершит работу
Спасибо огромне. Кажется разобрался... смысл такой что я передавал файлы пакетами из одной проги в другую и решил подстраховаться (размер файла я передавал в первую очередь тк если он неизвестен неизвесно когда прекращать принимать) ввести типа таймера для переконнекта. А на сколько я понял у меня цыкл после приема всех пакетов подвисал...
у меня он был завязан на
while ((bytes = recv(sClient, szRecvBuff, sizeof(szRecvBuff), 0)) > 0)
{