передача данных между потоками
От: rcon111  
Дата: 29.06.11 16:50
Оценка:
Добрый вечер.
возникла такая проблема, нужно передать значение переменной из одного потока в другой
как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...

обьявляем переменную
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)
   .... //// так вот это событие и не случается (((
}

Заранее спасибо за помощь.
Re: передача данных между потоками
От: abdab Россия  
Дата: 29.06.11 17:05
Оценка:
Здравствуйте, rcon111, Вы писали:

Проверьте что возвращает CreateThread, может поток вообще не запускается. Либо проверка флага выполняется до того как он устанавливается в другом потоке. Либо поток TMR не доходит до строчки установки флага. Вариантов много, тут лучше всего поможет отладчик
Re: передача данных между потоками
От: const_volatile  
Дата: 29.06.11 17:21
Оценка:
Здравствуйте, 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, то это всё усложняет и тремя строчками уже не обойтись.
Re: передача данных между потоками
От: okman Беларусь https://searchinform.ru/
Дата: 29.06.11 17:22
Оценка: 3 (1) +1
Здравствуйте, rcon111, Вы писали:

R>Добрый вечер.

R>возникла такая проблема, нужно передать значение переменной из одного потока в другой
R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...

R>
R>обьявляем переменную
R>BOOL timer;


R>...


Так попробуйте:
BOOL volatile timer;
Re: передача данных между потоками
От: ДимДимыч Украина http://klug.org.ua
Дата: 30.06.11 00:04
Оценка: 1 (1)
Здравствуйте, rcon111, Вы писали:

R>возникла такая проблема, нужно передать значение переменной из одного потока в другой

R>как я понимаю самое простое это обьявление глобальной переменной, но почемуто не получается...

1. Компилятор не знает, что переменная меняется в другом месте, поэтому имеет право для оптимизации выбросить условие. Здесь поможет volatile.
2. Нити могут работать на разных ядрах с некогерентными кэшами. Здесь поможет memory barrier.
3. Не гарантируется, что доступ к переменной будет атомарным. Здесь нужен либо атомарный тип, либо синхронизация, которя также выполнит роль memory barrier.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[2]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 03:49
Оценка:
Здравствуйте, abdab, Вы писали:

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


A>Проверьте что возвращает CreateThread, может поток вообще не запускается. Либо проверка флага выполняется до того как он устанавливается в другом потоке. Либо поток TMR не доходит до строчки установки флага. Вариантов много, тут лучше всего поможет отладчик


CreateThread возвращает 1, поток работает проверял, проверка флага проходит в цыкле while.... вот по этому и не понимаю в чем проблема(
Re[2]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 04:05
Оценка:
Здравствуйте, okman, Вы писали:

O>Так попробуйте:

O>
O>BOOL volatile timer;
O>


неполучается(((
Re[2]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 04:07
Оценка:
Здравствуйте, ДимДимыч, Вы писали:

ДД>1. Компилятор не знает, что переменная меняется в другом месте, поэтому имеет право для оптимизации выбросить условие. Здесь поможет volatile.

ДД>2. Нити могут работать на разных ядрах с некогерентными кэшами. Здесь поможет memory barrier.
ДД>3. Не гарантируется, что доступ к переменной будет атомарным. Здесь нужен либо атомарный тип, либо синхронизация, которя также выполнит роль memory barrier.

а можно поподробнее для меня темного )))
Re[2]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 04:22
Оценка:
Здравствуйте, 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 и мне нужно выйти из него когда завершится тот поток.
Re: передача данных между потоками
От: Uzumaki Naruto Ниоткуда  
Дата: 30.06.11 04:39
Оценка:
Поток в С++ представляется в виде статической функции (по умолчанию у процесса есть главный поток представленный методом main).
Создавая поток, вы передаете указатель на статическую функцию, которая будет обработчиком потока, по завершению которой поток завершается...
В эту функцию в качестве параметра можно передать любой блок памяти (в частности указатель на класс)... Остается только синхронизовать обращение к этому общему блоку памяти (или части) из разных потоков... для этого есть мьютерсы или violate...

Re[3]: передача данных между потоками
От: const_volatile  
Дата: 30.06.11 04:45
Оценка:
Здравствуйте, rcon111, Вы писали:

R>если честно, не совсем понял смысл всего этого ((( совсем я темный)

R>if(timer == 0) находится внутри цыкла while и мне нужно выйти из него когда завершится тот поток.

так бы сразу и сказал, надо чётче условия задачи формулировать. тогда переменная timer вобще не нужна, надо просто в цикле "слушать" хендл потока через WaitForSingleObject. причём если цикл у тебя кроме ожидания ничего не делает, можно вобще без него обойтись, достаточно задать INFINITE таймаут.

HANDLE thread = CreateThread (...);

// условие выхода из цикла
DWORD rc = WaitForSingleObject (thread, 0); // второй параметр - таймаут
if (rc != WAIT_TIMEOUT)
    break;
...
Re[4]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 05:34
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>так бы сразу и сказал, надо чётче условия задачи формулировать. тогда переменная timer вобще не нужна, надо просто в цикле "слушать" хендл потока через WaitForSingleObject. причём если цикл у тебя кроме ожидания ничего не делает, можно вобще без него обойтись, достаточно задать INFINITE таймаут.


_>
_>HANDLE thread = CreateThread (...);

_>// условие выхода из цикла
_>DWORD rc = WaitForSingleObject (thread, 0); // второй параметр - таймаут
_>if (rc != WAIT_TIMEOUT)
_>    break;
_>...
_>


сделал так, но пчемуто не получается, событие не происходит((( попробывал еще и через SetEvent тоже ничего...


HANDLE events;

DWORD WINAPI TMR(LPVOID lpParam)
{
    Sleep(3000);
    //MessageBox(0,0,0,0);
        SetEvent(events);

    return 1;
}

DWORD WINAPI NetThread(LPVOID lpParam)
{
.....................
        HANDLE tmr = CreateThread(NULL, 0, TMR, 0, 0, 0);
        events = CreateEvent(0, 1, 0, 0);
        DWORD dw1;// = WaitForSingleObject(events,1);
        DWORD dw2;

                while (....)
                  {
                   .......
           dw1 = WaitForSingleObject(events,0);
           if(dw1 != WAIT_TIMEOUT)
            {
                MessageBox(0, L"dw1", L"Error", 0);
                break;
            }
           dw2 = WaitForSingleObject(tmr,0);
           if(dw2 != WAIT_TIMEOUT)
            {
                MessageBox(0, L"dw1", L"Error", 0);
                break;
            }
                    }
............
}
Re[2]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 05:46
Оценка:
Здравствуйте, Uzumaki Naruto, Вы писали:

UN>Поток в С++ представляется в виде статической функции (по умолчанию у процесса есть главный поток представленный методом main).

UN>Создавая поток, вы передаете указатель на статическую функцию, которая будет обработчиком потока, по завершению которой поток завершается...
UN>В эту функцию в качестве параметра можно передать любой блок памяти (в частности указатель на класс)... Остается только синхронизовать обращение к этому общему блоку памяти (или части) из разных потоков... для этого есть мьютерсы или violate...

а можно поподробнее, как это делается. Спасибо.
Re[5]: передача данных между потоками
От: const_volatile  
Дата: 30.06.11 06:29
Оценка: 3 (1)
Здравствуйте, 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, и может ли он прерваться до того как тред завершит работу.
Re: передача данных между потоками
От: Caracrist https://1pwd.org/
Дата: 30.06.11 06:38
Оценка:
Здравствуйте, 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>

R>Заранее спасибо за помощь.

omp

DWORD WINAPI NetThread(LPVOID lpParam)
{
  ......
  BOOL timer = 1;
  
  #pragma omp parallel sections shared(timer)
  {
    #pragma omp section
    {
      TMR(); //CreateThread(NULL, 0, TMR, 0, 0, 0);
      timer = 0;
    }
    #pragma omp section
    {
      if(timer == 0)
        .... 
      }
    }
  }
}
~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: передача данных между потоками
От: rumit7  
Дата: 30.06.11 07:10
Оценка: 1 (1)
Здравствуйте, 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) Грегори Р.Эндрюс — Основы многопоточного, параллельного и распределенного программирования.
Re[2]: передача данных между потоками
От: FlamingWind Россия  
Дата: 30.06.11 08:51
Оценка:
Здравствуйте, Uzumaki Naruto, Вы писали:

UN>для этого есть мьютерсы или violate...


А разве не и? Насколько я понимаю, нужно использовать и мьютекс (чтобы не было общего доступа, когда один поток — читает, другой — пишет), и violate, дабы компилятор не кешировал переменную в регистре, а всегда получал ее актуальное значение из памяти.
Re[6]: передача данных между потоками
От: rcon111  
Дата: 30.06.11 09:10
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>
_>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)
{
Re[3]: передача данных между потоками
От: ДимДимыч Украина http://klug.org.ua
Дата: 30.06.11 11:31
Оценка: 3 (1)
Здравствуйте, rcon111, Вы писали:

R>а можно поподробнее для меня темного )))


Короче, обращайся к общей переменной только внутри критической секции (см. Critical Sections). Квалификатор volatile в данном случае не нужен.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[3]: передача данных между потоками
От: ДимДимыч Украина http://klug.org.ua
Дата: 30.06.11 12:07
Оценка: 2 (1)
Здравствуйте, 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
}
...

все будет нормально.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.