Здраствуйте.
Понимаю, что пост длинный, но постарайтесь дочитать до конца - тут есть над чем призадуматься.
Есть однонаправленый список. Один поток добавляет элементы в список. Ещё два потока удаляют элементы из списка - первый через 2 секунды, второй случайным образом "ассинхронно угадывает", какой элемент удалить.
Очередь в некотором смысле FIFO. То есть новые элементы добавляются в голову. А обработка начинается с головы (с самых молоды) и заканчивается хвостом (давно стоящие в очереди), следовательно они могут успеть созреть.
Есть класс диспетчер, который управляет доступом к спискам. Управление происходит через два объекта синхронизации. Один из них - m_sync_act - более "сильный" и отвечает за обработку элементов списка. Второй - m_sync_add - отвечает за переключени флага m_no_act. Если список не обрабатывается потоками удаления, то флаг выставлен в true, а новый элемент добавляется в голову очереди. Если список обрабатывается потоками удаления, то флаг выставлен в false, а новый элемент добавляется в голову вторичной очереди. Когда поток удаления будет освобождать доступ к основной очереди, то вторичная очередь добавиться в голову первичной.
И ещё, щас код переписал на коленке по быстрому из основного рабочего в упрощеном варианте, , так что за синтаксические ошибки извените. (Прошу прощенья, за выходные поправлю, если есть ляпы, но помощь нужна скорее, чем я дооформлю тему)
Проблему, из-за которой начал эту тему, можно назвать так: элементы в список попадают, но не обрабатываются (не выходят). Успешной обработкой я называю в данном случае печать на экран и удаление из списка.
Проверьте есть ли идеологические ошибки в моем коде
Объект сихрониза
Код |
// TSync.h #pragma once //+------------------------------------------------------------------+ //| Mutex synchronizer | //+------------------------------------------------------------------+ class TSync { private: HANDLE hMutex;
public: TSync() { hMutex = CreateMutex(NULL,FALSE,"MutexToProtectListDispatcherThread"); } ~TSync() { CloseHandle(hMutex); hMutex=NULL; } inline void Lock() { WaitForSingleObject(hMutex,INFINITE); } inline void Unlock() { ReleaseMutex(hMutex); } };
|
Описание диспетчера задач
Код |
// TListDispatcher.h
#pragma once #include "TSync.h"
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct ListItem { int num; DWORD localtime; DWORD timeout; ListItem *next; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class TListDispatcher { public: ListItem *m_head; ListItem *m_add_first; ListItem *m_add_end; ListItem *m_act_before; ListItem *m_act_item; int m_min_time_of_delay; int m_timeout; private: HANDLE m_thread; bool m_stopflag; public: volatile bool m_no_act; // флаг синхронизации TSync m_sync_act; // синхрозитор обработки переменных TSync m_sync_add; // синхрозитор добавления переменных public: TListDispatcher(); ~TListDispatcher(); //---- int Initialize(void); int Shutdown(void); //---- int Add(const int num); ListItem* GetNext(void); ListItem* DeleteThisAndGetNext(void); int Locking(void); int Unlocking(void); //---- void CheckTick(const int number); private: //---- void Process(void);
//---- static UINT __stdcall ThreadFuntion(LPVOID pParam); }; //+------------------------------------------------------------------+ extern TListDispatcher ExtListDisp;
|
Методы класса
Код |
// TListDispatcher.cpp
#include "TListDispatcher.h"
//---- TListDispatcher ExtListDisp; //+------------------------------------------------------------------+ //| конструктор по умолчанию | //+------------------------------------------------------------------+ TListDispatcher::TListDispatcher() : m_head(NULL),m_stopflag(TRUE), m_thread(NULL),m_no_act(TRUE), m_add_first(NULL),m_add_end(NULL), m_act_before(NULL),m_act_item(NULL), m_min_time_of_delay(0),m_timeout(2) { //---- } //+------------------------------------------------------------------+ //| деструктор по умолчанию | //+------------------------------------------------------------------+ TListDispatcher::~TListDispatcher() { ListItem * item; //---- убъем поток обработки Shutdown(); //---- удаляем данные, но надо бы залочиться m_sync_act.Lock(); m_sync_add.Lock(); //---- удалим их while(m_head!=NULL) { item=m_head->next; delete m_head; m_head=item; } while(m_add_first!=NULL) { item=m_add_first->next; delete m_add_first; m_add_first=item; } //---- m_head = NULL; m_stopflag = TRUE; m_thread = NULL; m_no_act = TRUE; m_add_first = NULL; m_add_end = NULL; m_act_before = NULL; m_act_item = NULL; //---- m_sync_add.Unlock(); m_sync_act.Unlock(); } //+------------------------------------------------------------------+ //| запуск потока обработки | //+------------------------------------------------------------------+ int TListDispatcher::Initialize(void) { UINT tid; //---- закрываем, если что-то осталось Shutdown(); //---- сбрасываем флаг остановки m_stopflag=FALSE; //---- запускаем поток обработки m_thread=(HANDLE)_beginthreadex(NULL,0,ThreadFuntion,(void*)this,0,&tid); //---- m_min_time_of_delay = 2; m_timeout = 2; //---- return(TRUE); } //+------------------------------------------------------------------+ //| Завершение рабочего потока | //+------------------------------------------------------------------+ int TListDispatcher::Shutdown(void) { //---- сначала затормозим все if(m_thread!=NULL) { //---- говорим пора остановиться m_stopflag=TRUE; //---- ждем пока объект не освободиться WaitForSingleObject(m_thread,INFINITE); //---- принудительно убиваем (не уверен, что теперь это обязательное действие, но надеюсь не повредит) CloseHandle(m_thread); m_thread=NULL; } //---- return(TRUE); } //+------------------------------------------------------------------+ //| Добавление нового элемента для обработки | //+------------------------------------------------------------------+ int TListDispatcher::Add(const int number) { //---- ListItem* item; if(num<1) return(FALSE); //---- m_sync_add.Lock(); //---- копируем указатель на начало очереди if(m_no_act==true){// если действий сейчас не производиться item = m_head; //---- выделим новый элемент if((m_head=new ListItem)==NULL) { //---- возвращаем старый указатель на начало списка m_head = item; m_sync_add.Unlock(); //---- скажем что памяти нету printf("Not enough memory"); //---- return(FALSE); } m_head->next = item; } else{ item = m_add_first; //---- выделим новый элемент if((m_add_first=new ListItem)==NULL) { //---- возвращаем старый указатель на начало списка m_add_first = item; m_sync_add.Unlock(); //---- скажем что памяти нету printf("Not enough memory"); //---- return(FALSE); } m_add_first->next = item; if(m_add_end==NULL)m_add_end = m_add_first; } //---- заполним поля нового элемента m_head->timeout = m_head->tradetime = time(NULL); m_head->num = number; //---- освобождаем синхронизацию m_sync_add.Unlock(); return(TRUE); } //+------------------------------------------------------------------+ //| Взять элемент | //+------------------------------------------------------------------+ ListItem* TListDispatcher::GetNext(void) { if(m_act_item==NULL){ m_act_item = m_head; m_act_before = NULL; } else{ m_act_before = m_act_item; m_act_item = m_act_item->next; } return m_act_item; } //+------------------------------------------------------------------+ //| Взять элемент и удалить | //+------------------------------------------------------------------+ ListItem* TListDispatcher::DeleteThisAndGetNext(void) { ListItem* del; del = m_act_item; if(m_act_item==m_head){ m_act_before = NULL; m_act_item = m_head = m_act_item->next; } else{ if(m_act_before!=NULL) m_act_before->next = m_act_item->next; m_act_item = m_act_item->next; } delete del; return m_act_item; } //+------------------------------------------------------------------+ //| Закрытие списка для добавления, пусть пользуються вторичным | //+------------------------------------------------------------------+ int TListDispatcher::Locking(void) { m_sync_act.Lock(); m_sync_add.Lock(); m_no_act = false; m_act_before = NULL; m_act_item = NULL; m_sync_add.Unlock(); return TRUE; } //+------------------------------------------------------------------+ //| Открытие списка для добавления, перемещаем данные из вторичного | //+------------------------------------------------------------------+ int TListDispatcher::Unlocking(void) { m_sync_add.Lock(); m_no_act = true; if(m_add_end!=NULL){// значит в втором списке хотя бы один элемент m_add_end->next = m_head; m_head = m_add_first; m_add_first = NULL; m_add_end = NULL; } m_act_before = NULL; m_act_item = NULL; m_sync_add.Unlock(); m_sync_act.Unlock(); return TRUE; } //+------------------------------------------------------------------+ //| Обработка элементов по истечении срока | //+------------------------------------------------------------------+ void TListDispatcher::Process(void) { ListItem *item; time_t BeginTime; //---- крутимся пока не скажут выходить while(m_stopflag==FALSE) { BeginTime=ExtServer->TradeTime(); //---- локируемся Locking(); //---- берем верхушку item=GetNext(); //---- крутимся пока не скажут выходить или не кончиться список while((m_stopflag==FALSE)&&(item!=NULL)) { if(m_min_time_of_delay>0){ if((item->tradetime+ExtProcessor.m_min_time_of_delay)<BeginTime){ if(ExtProcessor.m_timeout>0) if((item->timeout + ExtProcessor.m_timeout*60) < BeginTime){ //---- данные у нас надо хранить как зеницу ока printf("timeout %i\n",item->num); //---- освобождаем текущий элемент item = DeleteThisAndGetNext(); continue; } //---- обрабатываем текущий элемент printf("%i\n",item->num); //---- освобождаем текущий элемент item = DeleteThisAndGetNext(); } else{ item = GetNext(); } } else{ //---- обрабатываем текущий элемент printf("%i\n",item->num); //---- освобождаем текущий элемент item = DeleteThisAndGetNext(); } } Unlocking(); if(m_stopflag==FALSE)Sleep(100);//Sleep(500); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void TListDispatcher::CheckTick(const int number) { ListItem *item; if(number<1) return; Locking(); item=GetNext(); while(item!=NULL){ if(item->num == number){ //---- обрабатываем текущий элемент printf("checktick %i\n",item->num); //---- освобождаем текущий элемент item = DeleteThisAndGetNext(); } } else{ item=GetNext(); } } Unlocking(); }
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ UINT __stdcall TListDispatcher::ThreadFuntion(LPVOID pParam) { //---- передадим управление фукнции обработки if(pParam!=NULL) ((TMarketDispatcher *)pParam)->Process(); //---- завершаем поток _endthreadex(0); return(0); }
|
И использование данного класса. Естественно циклы только в нижнем примере бесконечные (здесь только для простоты иллюстрации) - while(true) -, в жизне там стоит флаг завершения обработки, как это было сделано в выше приведенном классе.
Код |
#include <windows.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <process.h>
#include "TListDispatcher.h"
UINT __stdcall ThreadCheck(LPVOID pParam) { while(true){ //---- передадим управление фукнции обработки ExtListDisp.CheckTick(rand(100)); Sleep(100); } //---- завершаем поток _endthreadex(0); return(0); }
void main(void) { int a=0; ExtListDisp.Initialize(); _beginthreadex(NULL,0,ThreadCheck,(void*)this,0,0); while(true){ a++; a=a%100; ExtListDisp.Add(a); Sleep(10); } ExtListDisp.Shutdown(); }
|
Это сообщение отредактировал(а) neosapient - 28.10.2007, 01:01
Присоединённый файл ( Кол-во скачиваний: 3 )
ListDisp.rar 3,54 Kb