Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Пул потоков: как избавиться от дэдлока 
:(
    Опции темы
Alca
Дата 13.1.2010, 13:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Принцип работы пула:
- Есть пул потоков (класс CXThreadPool порожденный от CXThread).
- Есть виртуальный метод uiOnRun (я его переопределяю в данном пуле CXThreadPool),
  в котором я поочереди запускаю потоки (задания) и добавляю указатели на эти потоки в std::list.
- Затем в том же uiOnRun жду окончания работы всех потоков на методе bWaitGroup (врапер над WaitForSingleObject).

- Когда поток отработал, он самоуничтожается (т.е. delete pPtr_ToThread делать не надо) и 
  удаляется соотв-щий указатель на объект потока из std::list. 

!!! Вот в чём затык !!! : 
- когда я жду на bWaitGroup, какой-то поток начинает завершаться (начинает работать метод _vOnExitTask) и
  т.к. все операции с std::list я лочу крит. секцией (CXCriticalSectionLocker, т.е. лок действует до конца блока), 
  то возникает дедлок
.
  
  
При использование метода bExitGroup(INFINITE):
Код

    CXThreadPool<CWorkThread> *thpTP = NULL;
    //...
    VOID vBtnExitGroup_OnClick() {
        g_bRes = thpTP->bExitGroup(INFINITE/*5000*/);
    }

    
получаю такой лог:
Код

[11:47:28] vBtnCreateGroup_OnClick
[11:47:28] _vOnEnterTask: #0
[11:47:28] _vOnEnterTask: #1
[11:47:28] _vOnEnterTask: #2
[11:47:28] _vOnEnterTask: #3
[11:47:28] Thread #0  0: qqq
[11:47:28] Thread #1  0: qqq
[11:47:28] Thread #2  0: qqq
[11:47:28] Thread #3  0: qqq
[11:47:29] Thread #0  1: www
[11:47:29] Thread #1  1: www
[11:47:29] Thread #2  1: www
[11:47:29] Thread #3  1: www
[11:47:29] Thread #0  2: eee
[11:47:29] Thread #1  2: eee
[11:47:29] Thread #2  2: eee
[11:47:29] Thread #3  2: eee
[11:47:30] Thread #0  3: qqq
[11:47:30] Thread #1  3: qqq
[11:47:30] Thread #2  3: qqq
[11:47:30] Thread #3  3: qqq
[11:47:30] Thread #0  4: www
[11:47:30] Thread #1  4: www
[11:47:30] Thread #3  4: www
[11:47:30] Thread #2  4: www
[11:47:31] Thread #0  5: eee
[11:47:31] Thread #1  5: eee
[11:47:31] Thread #3  5: eee
[11:47:31] Thread #2  5: eee
[11:47:31] vBtnExitGroup_OnClick
[11:47:31] _vOnExitTask: #0        //здесь типа повисли


  
Как мне решить эту проблему, может выстроить другую архитектуру пула?

Вот исходники:

Код

#include <XLib/CXString.h>


/****************************************************************************
*    Public methods                                                          
*                                                                            
*****************************************************************************/

//---------------------------------------------------------------------------
//TODO: + CXThreadPool
template<class TaskT>
CXThreadPool<TaskT>::CXThreadPool(BOOL bIsPaused,      BOOL bIsAutoDelete,      BOOL bIsUsingCOM, 
                                  BOOL bIsGroupPaused, BOOL bIsGroupAutoDelete, BOOL bIsGroupUsingCOM
) :
    CXThread              (bIsPaused, bIsAutoDelete, bIsUsingCOM),
    _m_cbIsGroupPaused    (bIsGroupPaused),            
    _m_cbIsGroupAutoDelete(bIsGroupAutoDelete),        
    _m_cbIsGroupUsingCOM  (bIsGroupUsingCOM),            
    _m_uiMaxRunningTasks  (0),    
    _m_uiNumTasks          (0),    
    _m_uiCurrTask          (0)
{
    /*LOG*/_m_clLog.bWrite(_T("Construct pool"));
}
//---------------------------------------------------------------------------
//TODO: + ~CXThreadPool
template<class TaskT>
CXThreadPool<TaskT>::~CXThreadPool() {
    /*LOG*/_m_clLog.bWrite(_T("Destroy pool"));
}
//---------------------------------------------------------------------------

/****************************************************************************
*    действия с группой                                                     
*                                                                            
*****************************************************************************/

//---------------------------------------------------------------------------
//TODO: - bCreateGroup ()
template<class TaskT>
BOOL CXThreadPool<TaskT>::bCreateGroup(UINT uiStackSize, const pThreadProc ptfStartAddress, VOID *pvParam, UINT uiNumTasks, UINT uiMaxRunningTasks) {
    /*DEBUG*/XASSERT_RET(0    <= uiStackSize,       FALSE);    //TODO: - MaxValue
    /*DEBUG*/XASSERT_RET(0    == ptfStartAddress,   FALSE);
    /*DEBUG*/XASSERT_RET(NULL != pvParam,           FALSE);
    /*DEBUG*/XASSERT_RET(0    <  uiNumTasks,        FALSE);
    /*DEBUG*/XASSERT_RET(0    <  uiMaxRunningTasks, FALSE);

    BOOL bRes = FALSE;

    //-------------------------------------
    //рабочие потоки
    _m_uiStackSize       = uiStackSize;                
    _m_ptfStartAddress   = ptfStartAddress;            
    _m_pvParam           = pvParam;    
    _m_uiNumTasks         = uiNumTasks;
    _m_uiMaxRunningTasks = uiMaxRunningTasks;

    //-------------------------------------
    //пул
    CHECK_DO(TRUE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool is running")); TRUE);

    bRes = bCreate(0, 0, NULL);
    XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: - bResumeGroup ()
template<class TaskT>
BOOL CXThreadPool<TaskT>::bResumeGroup() {
    /*DEBUG*/

    BOOL bRes = FALSE;

    //-------------------------------------
    //рабочие потоки
    {
        CXCriticalSectionLocker CS(_m_csList);

        for (std::list<TaskT *>::iterator it = _m_lstpthTasks.begin(), end = _m_lstpthTasks.end();  it != end;  ++ it)    {
            CHECK_DO(FALSE == (*it)->bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Not running")); continue);

            bRes = (*it)->bResume();
            /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);
        }
    }

    //-------------------------------------
    //пул
    CHECK_DO(FALSE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool not running")); TRUE);

    bRes = bResume();        
    XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: - bPauseGroup ()
template<class TaskT>
BOOL CXThreadPool<TaskT>::bPauseGroup() {
    /*DEBUG*/

    BOOL bRes = FALSE;

    //-------------------------------------
    //пул
    CHECK_DO(FALSE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool not running")); TRUE);

    bRes = bPause();        
    XASSERT_RET(FALSE != bRes, FALSE);

    //-------------------------------------
    //рабочие потоки
    {
        CXCriticalSectionLocker CS(_m_csList);

        for (std::list<TaskT *>::iterator it = _m_lstpthTasks.begin(), end = _m_lstpthTasks.end();  it != end;  ++ it)    {
            CHECK_DO(FALSE == (*it)->bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Not running")); continue);

            bRes = (*it)->bPause();
            /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);
        }
    }

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: - bExitGroup ()
template<class TaskT>
BOOL CXThreadPool<TaskT>::bExitGroup(ULONG ulTimeout) {
    /*DEBUG*/

    BOOL bRes = FALSE;

    //-------------------------------------
    //пул
    CHECK_DO(FALSE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool not running")); TRUE);

    bRes = bExit(ulTimeout/*INFINITE*/);        
    XASSERT_RET(FALSE != bRes, FALSE);

    //-------------------------------------
    //рабочие потоки
    {
        CXCriticalSectionLocker CS(_m_csList);

        for (std::list<TaskT *>::iterator it = _m_lstpthTasks.begin(), end = _m_lstpthTasks.end();  it != end;  ++ it)    {
            CHECK_DO(FALSE == (*it)->bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Not running")); continue);

            bRes = (*it)->bExit(ulTimeout);
            /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);

            ////bRes = (*it)->bWait(ulTimeout);
            /////*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);
        }
    }

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: - uiKillGroup (убийство рабочих потоков)
template<class TaskT>
BOOL CXThreadPool<TaskT>::bKillGroup(ULONG ulTimeout) {
    /*DEBUG*/

    BOOL bRes = FALSE;

    //-------------------------------------
    //рабочие потоки
    {
        CXCriticalSectionLocker CS(_m_csList);
        
        for (std::list<TaskT *>::iterator it = _m_lstpthTasks.begin(), end = _m_lstpthTasks.end();  it != end;  ++ it)    {
            CHECK_DO(FALSE == (*it)->bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Not running")); continue);

            bRes = (*it)->bKill(ulTimeout);
            /////*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);
        }
    }

    //-------------------------------------
    //пул
    CHECK_DO(FALSE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool not running")); TRUE);

    bRes = bKill(ulTimeout);        
    /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: - bWaitGroup (ожидание завершения рабочих потоков (ждем по одному))
template<class TaskT>
BOOL CXThreadPool<TaskT>::bWaitGroup(ULONG ulTimeout) {
    /*DEBUG*/

    BOOL bRes = FALSE;

    //-------------------------------------
    //рабочие потоки
    {
        CXCriticalSectionLocker CS(_m_csList);

        for (std::list<TaskT *>::iterator it = _m_lstpthTasks.begin(), end = _m_lstpthTasks.end();  it != end;  ++ it)    {
            CHECK_DO(FALSE == (*it)->bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Not running")); continue);
    
            bRes = (*it)->bWait(ulTimeout);
            /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);
        }
    }

    //-------------------------------------
    //пул - !ожидание самого себя! - skipping
    //--CHECK_DO(FALSE == bIsRunning(), /*LOG*/g_clLog.bWrite(_T("Pool not running")); TRUE);
    //--
    //--bRes = bWait(ulTimeout);        
    //--XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------

/****************************************************************************
*                                                        
*                                                                            
*****************************************************************************/

//---------------------------------------------------------------------------
//TODO: - bPushTask (добавляем элемент в очередь, увеличиваем счетчик семафора на 1)
template<class TaskT>
BOOL CXThreadPool<TaskT>::bPushTask(VOID *pvNewItem) { 
    BOOL bRes = FALSE;

    bRes = _m_semSemaphore.bRelease(1, NULL); 
    /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
} 
//---------------------------------------------------------------------------
//TODO: - bPopTask (если очередь пуста, то потоки, вызвавшие этот метод, будут находиться в ожидании... )
template<class TaskT>
BOOL CXThreadPool<TaskT>::bPopTask(VOID *pvItem) { 
    /*DEBUG*/

    BOOL bRes  = FALSE;

    bRes = _m_semSemaphore.bWait(INFINITE);
    /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
} 
//---------------------------------------------------------------------------



/****************************************************************************
*    Protected methods                                                       
*                                                                            
*****************************************************************************/

//---------------------------------------------------------------------------
//TODO: - uiOnRun
template<class TaskT>
UINT CXThreadPool<TaskT>::uiOnRun(VOID *pData) { 
    /*DEBUG*/

    UINT uiRes = 0;
    BOOL bRes  = FALSE;

    //-------------------------------------
    //ставим семафор
    bRes = _m_semSemaphore.bCreate(NULL, _m_uiMaxRunningTasks, _m_uiMaxRunningTasks, sCreatePlainGUID().c_str());  
    /*DEBUG*/XASSERT_RET(FALSE != bRes, 0);
    
    //-------------------------------------
    //крутим цикл
    /*DEBUG*/XASSERT(true == _m_lstpthTasks.empty());
    _m_lstpthTasks.clear();  

    for ( ; ; ) {
        //-------------------------------------
        //не пора ли выйти или приостановиться
        bRes = bIsTimeToExit();        
        CHECK_DO(TRUE == bRes, break);

        //-------------------------------------
        //для останова (если выполнены все задания - выход)
        CHECK_DO(_m_uiCurrTask >= _m_uiNumTasks - 1, break);        

        //-------------------------------------
        //ждем пока освободиться хоть один поток
        bRes = bPopTask(NULL);                                //_m_semSemaphore.bWait
        /*DEBUG*/XASSERT_DO(FALSE != bRes, break);          

        //-------------------------------------
        //не пора ли выйти или приостановиться
        bRes = bIsTimeToExit();        
        CHECK_DO(TRUE == bRes, break);          

        //-------------------------------------
        //запуск потока
        try {
            TaskT *pthTemp = new TaskT(_m_cbIsGroupPaused, _m_cbIsGroupAutoDelete, _m_cbIsGroupUsingCOM);        
            /*DEBUG*/XASSERT_DO(NULL != pthTemp, break);   

                   pthTemp->m_uiIndex = _m_uiCurrTask;
                   pthTemp->vAttachHandler_OnEnter( CLOSURE(this, &CXThreadPool::_vOnEnterTask) );
                   pthTemp->vAttachHandler_OnExit ( CLOSURE(this, &CXThreadPool::_vOnExitTask ) );

            bRes = pthTemp->bCreate(_m_uiStackSize, _m_ptfStartAddress, _m_pvParam);        
            /*DEBUG*/XASSERT_DO(FALSE != bRes, break);      
            bRes = pthTemp->bResume();            
            /*DEBUG*/XASSERT_DO(FALSE != bRes, break);       

            {
                CXCriticalSectionLocker CS(_m_csList);

                _m_lstpthTasks.push_back(pthTemp);
            }

            _m_uiCurrTask ++;
        } catch (...) {
            /*DEBUG*/XASSERT(FALSE);    
        }    
    } //for


    //-------------------------------------
    //ждем пока завершаться дочерние потоки (ждем по одному)
    //::Sleep(15000);
    
    bRes = bWaitGroup(INFINITE);       //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !!! дедлок !!!
    /*DEBUG*/XASSERT_RET(FALSE != bRes, 0);  


    return uiRes;
}
//---------------------------------------------------------------------------



/****************************************************************************
*    Private methods                                                         
*                                                                            
*****************************************************************************/


//---------------------------------------------------------------------------
//TODO: - _vOnExitTask ()
template<class TaskT>
VOID CXThreadPool<TaskT>::_vOnExitTask(CXThread *pthSender)  {
    /*DEBUG*/

    TaskT *pthThis = static_cast<TaskT *>(pthSender);
    /*DEBUG*/XASSERT_DO(NULL  != pthThis,               return);
    /*DEBUG*/XASSERT_DO(FALSE != pthThis->bIsRunning(), return);

    
    /*DEBUG*/XASSERT_DO(false == _m_lstpthTasks.empty(), return);
    {
        CXCriticalSectionLocker CS(_m_csList);

        _m_lstpthTasks.remove(pthThis);
    }
    /*DEBUG*/XASSERT(NULL != pthThis);

    BOOL bRes = FALSE;

    bRes = bPushTask(NULL);    //_m_semSemaphore.bRelease
    /*DEBUG*/XASSERT_DO(FALSE != bRes, return);

    /*LOG*/_m_clLog.bWrite(_T("_vOnExitTask: #%i"), pthThis->m_uiIndex);
}
//---------------------------------------------------------------------------



Это сообщение отредактировал(а) Alca - 13.1.2010, 13:47


--------------------
PM WWW ICQ Skype Jabber   Вверх
Earnest
Дата 13.1.2010, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Если я правильно поняла: во время ожидания у тебя список заблокирован и именно это является причиной deadlock, т.к. поток не может себя удалить.
Самое логичное - избавиться от блокировки на время ожидания. Жто и само по себе вредно, все блокировки должны быть короткими.
Например, скопировать список (т.е. хандлы потоков и ждать их). Но я вообще не понимаю, зачем тебе ждать через WaitForSingleObject. Почему не Multiple? 


--------------------
...
PM   Вверх
Lazin
Дата 13.1.2010, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Цитата(Earnest @  13.1.2010,  14:01 Найти цитируемый пост)
Например, скопировать список (т.е. хандлы потоков и ждать их). Но я вообще не понимаю, зачем тебе ждать через WaitForSingleObject. Почему не Multiple?  

а почему не IOCP, или не thread pool api?
PM MAIL Skype GTalk   Вверх
Alca
Дата 13.1.2010, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Цитата

Если я правильно поняла: во время ожидания у тебя список заблокирован и именно это является причиной deadlock, т.к. поток не может себя удалить

Т.к. залочен std::list и поток не может себя удалить из списка

Цитата

Почему не Multiple?

Потому что WaitForMultipleObjects может ждать не больше 64-х хендлов и
поэтому все равно прийдется крутить цикл.  (позже переделаю все-таки на мальтипл).

Цитата

Самое логичное - избавиться от блокировки на время ожидания

Тогда вылетают STL-вские эссерты

Цитата

а почему не IOCP, или не thread pool api?

thread pool api не использкется, хочу сваять без него и к тому же, еще не разобрался в IOCP.  smile 


Это сообщение отредактировал(а) Alca - 13.1.2010, 14:17


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 13.1.2010, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



семафор нужно поставить...

1. создаем семафор на N единиц
2. создаем N потоков
3. каждый поток, при завершении, вызывает WaitForSingleObject для этого семафора
4. после чего можно выполнять vBtnExitGroup_... и т.п., т.е. после Wait'а все семафоры точно прошли "тело",
это называется барьер (barrier)

если нужно динамически увеличить число потоков, вызываем ReleaseSemaphore с числом добавляемых потоков

Добавлено через 3 минуты и 49 секунд
блин smile перепутал сигнальные состояния,
щас подумаем...


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 13.1.2010, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Цитата

семафор нужно поставить...

Так он у меня и есть (_m_semSemaphore).

Добавлено @ 14:27
Первые три пункта у меня так и работают, а
vBtnExitGroup_OnClick() вызывается из главного (основного) потока (это кнопка на окне).


Это сообщение отредактировал(а) Alca - 13.1.2010, 14:29


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 13.1.2010, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



не не, я же говорю, перепутал
где-то у нас тут была реализация обратного семафора

принцип где-то такой:
Код

LONG sem = 0;
_InterlockedAdd( &sem, N );
... запуск N потоков
... тело каждого из N потоков
if( _InterlockedDecrement( &sem ) ){
  ::WaitForSingleObject( hBarrier, INFINITE );
}else{
  ::SetEvent( hBarrier );
}
... пост обработка


Добавлено через 1 минуту и 28 секунд
hBarrier - неавтомат


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 13.1.2010, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Цитата

реализация обратного семафора

и что он должен  делать? Смысл какой?


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 13.1.2010, 14:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Alca @  13.1.2010,  16:25 Найти цитируемый пост)
vBtnExitGroup_OnClick() вызывается из главного (основного) потока (это кнопка на окне).

значит надо сделать в vBtnExitGroup_OnClick ожидание прохода барьера,
для моего варианта это будет так:
Код

void vBtnExitGroup_OnClick( ... ){
  if( _InterlockedExchange( &sem, 0 ) ){
    ::SetEvent( hBarrier );
  }
  ... что-то делаем, для освобождения ресурсов
}

Добавлено @ 14:59
Цитата(Alca @  13.1.2010,  16:52 Найти цитируемый пост)
и что он должен  делать? Смысл какой? 

смысл - сигнализировать когда счетчик нулевой
стандартный семафор сигнализирует пока счетчик ненулевой

Это сообщение отредактировал(а) GremlinProg - 13.1.2010, 15:00


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 13.1.2010, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Цитата

смысл - сигнализировать когда счетчик нулевой

и что это даст в моем случае?  smile

Добавлено через 40 секунд
Объясни алгоритм, пж. 


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 13.1.2010, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(GremlinProg @  13.1.2010,  16:55 Найти цитируемый пост)
ожидание прохода барьера

это не ожидание, это обрыв семафора, т.е. блокировка всех оставшихся в нем единиц одним махом
_InterlockedExchange при этом вернет число потоков, которые не прошли барьер

для ожидания в vBtnExitGroup_OnClick, надо прокрутить WaitForSingleObject для дополнительного семафора N раз,
а в постобработку каждого потока добавить ReleaseSemaphore на единицу

Добавлено @ 15:26
Цитата(Alca @  13.1.2010,  17:08 Найти цитируемый пост)
и что это даст в моем случае?

в твоем случае ( когда vBtnExitGroup_OnClick - в основном потоке) достаточно будет сделать последнее:
Цитата(GremlinProg @  13.1.2010,  17:16 Найти цитируемый пост)
надо прокрутить WaitForSingleObject для семафора N раз,
а в постобработку каждого потока добавить ReleaseSemaphore для этого семафора на единицу 


если кроме vBtnExitGroup_OnClick критических мест нет, то барьер (на обратном семафоре) в потоках уже будет не нужен


Это сообщение отредактировал(а) GremlinProg - 13.1.2010, 15:41


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
GremlinProg
Дата 13.1.2010, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



хорошо объяснил: сам с собой поспорил, исправил, разве что не наказал :)

Цитата(GremlinProg @  13.1.2010,  17:16 Найти цитируемый пост)
надо прокрутить WaitForSingleObject для семафора N раз,
а в постобработку каждого потока добавить ReleaseSemaphore для этого семафора на единицу

это будет означать, что цикл в основном потоке завершится только тогда, когда все N потоков вызовут ReleaseSemaphore,
т.е., что называется, "пройдут барьер"


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 13.1.2010, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



GremlinProg, спасибо. Буду разбираться. 


--------------------
PM WWW ICQ Skype Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0625 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.