Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизация потоков. Unhandled exception: 0xC0000005: Access Violation. VC++ API 
:(
    Опции темы
Allest
Дата 26.8.2004, 21:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 17.9.2003
Где: Санкт-Петербург

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



Мне нужно чтобы поток выделял память, сохранял в vector, а потом завершался, и при этом к vector имеют доступ основной поток, поэтому ещё и синхронизация нужна.
Вроде всё делаю правильно, но почему-то происходит ошибка доступа к памяти (как я понял): Unhandled exception in Test.exe: 0xC0000005: Access Violation.

Вот мой код с ошибкой, можно сразу создать новое win32 application, и запустить.
Здесь 10 потоков CAfcTest выделяют память и сохраняют в vector, а в деструкторе память освобождается. В общем, помогите плиз найти ошибку или другое решение
Код

class CAfcTest
{
public:
HANDLE m_hThread;
CRITICAL_SECTION m_Crit;
BOOL m_bRun;
std::vector<DWORD*> m_vec;

public:
CAfcTest();
virtual ~CAfcTest();
BOOL WorkProc();
BOOL Create();
VOID Destroy();
BOOL IsActive() const;
};

#define MYTHREAD_COUNT 10

int APIENTRY WinMain(HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR     lpCmdLine,
                    int       nCmdShow)
{
 {
 CAfcTest test[MYTHREAD_COUNT];
 INT   i;
 for (i = 0; i < MYTHREAD_COUNT; i++)
  test[i].Create();
 for (i = 0; i < 5; i++)
  Sleep(1000);
 for (i = 0; i < MYTHREAD_COUNT; i++)
  test[i].Destroy();
}
::MessageBox(NULL, "complite", "test", MB_OK);
return 0;
}

inline
CAfcTest::CAfcTest()
{
::InitializeCriticalSection(&m_Crit);
}

inline
CAfcTest::~CAfcTest()
{
std::vector<DWORD*>::const_iterator
 iter, iterEnd;
DWORD *pData;
::EnterCriticalSection (&m_Crit);
iter = m_vec.begin();
iterEnd = m_vec.end();
while (iter != iterEnd)
{
 pData = (*iter);
 if (pData)
  delete pData;
 iter++;
}
m_vec.clear();
::LeaveCriticalSection (&m_Crit);
::DeleteCriticalSection(&m_Crit);
}

inline
DWORD WINAPI fnTestProc(VOID* lpParameter)
{
CAfcTest* pThread = (CAfcTest*)lpParameter;

do
{
}
while (pThread->WorkProc());
CloseHandle(pThread->m_hThread);
pThread->m_hThread = NULL;
return 0;
}

inline
BOOL CAfcTest::Create()
{
DWORD dwThreadId;
m_bRun = TRUE;
return ((m_hThread = CreateThread(NULL, 0, fnTestProc, (VOID*)this, 0, &dwThreadId)) != NULL);
}

inline
VOID CAfcTest::Destroy()
{
if (!IsActive())
 return;
::EnterCriticalSection (&m_Crit);
m_bRun = FALSE;
::LeaveCriticalSection (&m_Crit);
if (WaitForSingleObject(m_hThread, 1000) != WAIT_OBJECT_0)
{
 ::TerminateThread(m_hThread, 1);
 CloseHandle(m_hThread);
 m_hThread = NULL;
}
}

inline
BOOL CAfcTest::WorkProc()
{
::EnterCriticalSection (&m_Crit);
DWORD *pData = new DWORD;
m_vec.push_back(pData);
::LeaveCriticalSection (&m_Crit);

return m_bRun;
}

inline
BOOL CAfcTest::IsActive() const
{
DWORD dwExitCode;
return (m_hThread && ::GetExitCodeThread(m_hThread, &dwExitCode) && (dwExitCode == STILL_ACTIVE));
}


PM ICQ   Вверх
Олег М
Дата 27.8.2004, 06:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

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



Цитата(Allest @ 27.8.2004, 00:38)
do { } while (pThread->WorkProc());

У тебя функция WorkProc() выполняется хрен знает сколько раз. Ошибка происходит, когда на миллион-какой-то итерации происходит переполнение памяти. А ты чего ожидал? Память-то не резиновая.
PM MAIL ICQ   Вверх
Allest
Дата 27.8.2004, 21:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 17.9.2003
Где: Санкт-Петербург

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



В смысле в фунции много памяти выделяется из-за этого
Код
DWORD *pData = new DWORD;
?
А если сразу освобождать, то всё равно ошибка, т.е. если передалать так
Код

BOOL CAfcTest::WorkProc()
{
::EnterCriticalSection (&m_Crit);
DWORD *pData = new DWORD;
if (pData)
 delete pData;// сразу освобождаю
::LeaveCriticalSection (&m_Crit);

return m_bRun;
}


PM ICQ   Вверх
Олег М
Дата 29.8.2004, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

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



Цитата(Allest @ 28.8.2004, 00:59)
В смысле в фунции много памяти выделяется из-за этогоКод  DWORD *pData = new DWORD;  ?

В смысле да. Ты нафига постоянно-то это вызываешь? Если не можешь понять что ты делаешь - вот полный аналог твоей программы
Код

void main
{
for(;;) {DWORD *ptr=new DWORD;}
}

Посмотри как это будет работать.
Тебе вообще, что надо сделать? Расскажи задачу поподробнее.
PM MAIL ICQ   Вверх
Allest
Дата 29.8.2004, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 17.9.2003
Где: Санкт-Петербург

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



Спасибо за желание помочь. Думаю я понял почему появлялась ошибка: я вызывал 10 thread и каждый асихронно вызывал new и delete, из-за этого иногда 2 потока захватывали один и тот же блок памяти, а потом один из них освобождает эту память, а у другого остаётся указатель в "никуда" и при его вызове delete возникает та самая ошибка.
Или я ошибаюсь? Ведь нединамические переменные тоже память берут, но с ними проблем не было в отличае от созданных с помощью new.
Код

VOID WorkProc()
{
INT arrStaticMemory[1000];// вот эта память как-то выделяется и освобождается и никому не мешает
}

А задача была у меня создать файловую панель типа как в TotalCommander, но проще: список файлов в ListView, и icons, ассоциируемые с файлами должны были загружаться в thread. Для этого после построения списка файлов запускал thread, который извлекал icons и добавлял HICON в vector и постил сообщение окну списка, чтобы тот прикрутил себе извлечённые icons.
Как это сделать?

PM ICQ   Вверх
Олег М
Дата 30.8.2004, 05:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

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



Цитата(Allest @ 29.8.2004, 23:27)
Думаю я понял почему появлялась ошибка: я вызывал 10 thread и каждый асихронно вызывал new и delete,

Думаю, ты нифига не понял. Потоки у тебя синхронизируются совершенно нормально - нафига, иначе, критические секции существуют. А ошибка у тебя вылезает именно из-за переполнения памяти - покажи, где ты это контролируешь, если не согласен. Я поставил вот так и посмотрел сколько раз у тебя вызывается new
Код

static int n=0;
BOOL CAfcTest::WorkProc()
{
::EnterCriticalSection (&m_Crit);
DWORD *pData = new DWORD;
m_vec.push_back(pData);
++n;
::LeaveCriticalSection (&m_Crit);
return m_bRun;
}

получилось дохрена. И исключение срабатывает, похоже в m_vec.push_back(pData) - массивы тожке не резиновые.
А вообще зачем ты хранишь указатели на DWORD? Храни тогда уж просто значение std::vector<DWORD> m_vec.
Цитата(Allest @ 29.8.2004, 23:27)
А задача была у меня создать файловую панель типа как в TotalCommander, но проще: список файлов в ListView, и icons, ассоциируемые с файлами должны были загружаться в thread. Для этого после построения списка файлов запускал thread, который извлекал icons и добавлял HICON в vector и постил сообщение окну списка, чтобы тот прикрутил себе извлечённые icons. Как это сделать?

Во первых потоки делай с приоритетом ниже нормального - иначе они нет смысла - они забьют основной поток. В вторых так и делай - загружай иконки в массив, синхронизируй с помощью критических секций, и чер определённое время, например на каждые 10 иконок посылай сообщени - SendMessage. В функции потока контролируй какую-нибудь булевскую переменную - завершение потока. Типа того
Код

while (bContinue)
{
///Функция загрузки
::WaitForSingleObject(ev,INFINITE);// Ожидаем следующей команды загрузки
}
return;

ev - событие с ручным сбросом - чтобы поток останавливался, когда ничего загружать не надо. Когда завершаешь поток делай
Код

bContinue=false;
SetEvent(ev);
WaitForSinlgeObject(hTread,INFINITE)

TerminateThread делать не надо
PM MAIL ICQ   Вверх
Allest
Дата 30.8.2004, 10:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 17.9.2003
Где: Санкт-Петербург

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



Цитата
А ошибка у тебя вылезает именно из-за переполнения памяти - покажи, где ты это контролируешь, если не согласен.

Не из-за переполнения памяти, повторяю
Цитата

А если сразу освобождать, то всё равно ошибка, т.е. если передалать так

BOOL CAfcTest::WorkProc()
{
::EnterCriticalSection (&m_Crit);
DWORD *pData = new DWORD;
if (pData)
delete pData;// сразу освобождаю
::LeaveCriticalSection (&m_Crit);

return m_bRun;
}


Цитата

Потоки у тебя синхронизируются совершенно нормально - нафига, иначе, критические секции существуют.

Всё правильно, но для того чтобы синхронизировать доступы к общей памяти нужно чтобы все потоки имели одну крит.секцию, а моём певоначальном коде у каждого потока была своя крит.секция.
Цитата
И исключение срабатывает, похоже в m_vec.push_back(pData)

Кстати, а как его перехватить?
А за советы спасибо.
PM ICQ   Вверх
Олег М
Дата 30.8.2004, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

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



Цитата(Allest @ 30.8.2004, 13:36)
Всё правильно, но для того чтобы синхронизировать доступы к общей памяти нужно чтобы все потоки имели одну крит.секцию, а моём певоначальном коде у каждого потока была своя крит.секция.

Точно, а я и не обратил внимания. Переделал уже?
Цитата(Allest @ 30.8.2004, 13:36)
Кстати, а как его перехватить?

Из МСДН:
Код

 try
  {
     vector<int, stingyallocator< int > > myv;
     for ( int i = 0; i < 11; i++ ) myv.push_back( i );
  }
  catch ( exception &e )
  {
     cerr << "Caught " << e.what( ) << endl;
     cerr << "Type " << typeid( e ).name( ) << endl;
  };

PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

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


 




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


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

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