tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« : 23-02-2009 12:56 » |
|
Здравствуйте. Есть программа. Она, по сути, является блоком управления большой системой по Ethernet. Управляет она множеством (пока 20, но может быть до 272) одинаковых СВЧ-блоков. На каждом блоке запущен сервер, а программа к нему подключается, т. е. она клиент. За каждое подключение отвечает один из 20 объектов класса BK. Этот класс по таймеру проверяет подключение. Прверка - это тестовая посылка. Ответ от блока должен быть такой же и время ответа 500 мс. Если ответа нет, то считаем что блок не подключен. Если Блок не подключен, то раз в секунду пробуем подключится. В итоге имеем множество таймеров и потоков. Я писал и компилировал все на 1-ядерной машине. Не было возможности на 2-х или 4-хядерном компе опробовать. Как оказалось позже программа на 2-хядерном компьютере сильно нагружает 1 процессор. Но это не критично. Проблемма в том, что она сильно висит. Такое впечатление, что там очень долгие циклы везде. Приотключении 2-ого ядра программа работает абсолютно нормально, т. е. хорошо грузит процессор, но ничего не висит. Подскажите, пожалуйста, в какую сторону копать и в чем может быть проблемма? Я думаю, что проблема в синхронизации всех этих опросов подключения на таймерах с работой системы с 2-умя ядрами, но как это решить просто не понимаю. Или хотя бы можно как-то в программе написать, чтоб она пользовала только одно ядро.
P.S. Пробовал чтавить, чтоб она работала только на 2-ом ядре - та же проблема.
Подскажите, пожалуйста, может кто-то сталкивался с подобным.
|
|
|
Записан
|
|
|
|
Serg79
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #1 : 23-02-2009 14:15 » |
|
Или хотя бы можно как-то в программе написать, чтоб она пользовала только одно ядро.
Можно конечно привязывать все потоку к одному процессору (считай ядру), смотри системный вызов: DWORD_PTR SetThreadAffinityMask ( HANDLE hThread, // handle to thread DWORD_PTR dwThreadAffinityMask // thread affinity mask ); Советую так же посмотреть в сторону функции: BOOL QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, // starting address PVOID Context, // function data ULONG Flags // worker options );
которая позволит организовать работу всего твоего хозяйства в пуле потоков и возложит всю работы по созданию, привязке к процессорам потоков и т.п. на Windows.
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #2 : 24-02-2009 06:10 » |
|
1. Начни с проблемы производительности. Судя по описанию твоя программа не должна нагружать CPU. 2. Какие общие данные есть у потоков? 3. Как часто происходит проверка подключения и каким образом? 4. Может ты злоупотребаяешь объектами ядра и переключением контекста? (перевыдения памяти, пересоздание сокетов, частое обращение к сокетам и т.д. и т.п.) 5. Какой тип сокетов используется? 6. Второе ядро реальное или виртуальное? 7. Читай побольше Саттера( http://herbsutter.wordpress.com/). Например: http://www.ddj.com/hpc-high-performance-computing/214100002
|
|
|
Записан
|
Странно всё это....
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #3 : 24-02-2009 08:44 » |
|
Спасибо за ответы. Начну с конца. 7. Буду читать больше, это вообще моя первая программа на С++. Я перечитал множество литературы, и может решил бы эту проблему еще при написании, если бы писал на 2-ядерном процессоре. На 1-ядерном все нормально работало. 6. Второе ядро реальное. Intel CoreDuo E8200 по-моему. 5. Сокет Асинхронный использую. 4. Может и злоупотребляю, но не знаю как можно это посмотреть. У меня были проблемы с памятью, но я переписал немного кода через указатели, а не через статические объекты и стало все нормально. Повторюсь, это моя первая программа и писал я её, скорее всего, далеко не самыми оптимальными методами, но и на 2-ядерном с отключением именно 2-го ядра все нормально работает. 3. Проверка подключения происходит так: Сокет пробует подключится. Если подключился, то ставлю таймер №1 на 500 мс. По этому таймеру шлем тест-посылку. В методе OnRec() сбрасываю и опять стартую таймер №2 500 мс. Если сработает таймер №2 - то посылка не пришла воворемя. Сокет при этом закрываю, открываю заново и пытаюсь подключится. Извините, в первом посте немного неправду написал (давно программу не видел). Если Сокет не подключен, то я пробую просто подключиться, а не жду 1 секунду. Может здесь много сокетов пересоздаю, но по-другому не получается. Если идет обрыв связи, то сокет не всегда знает, что он отключился и не хочет подключаться. Поэтому я и закрываю его насильно, а потом создаю заново. 2. Про потоки я не правильно, наверное, выразился. Отдельные потоки я не создаю. Я имел ввиду, что сокеты каждый работает в своем потоке. В этом смысле они никак не пересекаются, т.е. между сокетами, да и вообще между объектами взаимосвязи никакой нет. 1. Я бв рад начать с производительности, но не знаю как померять её самую. Да желательно так чтоб поменять что-то в программе и померять, потом опять поменять и посмотреть. Тгда може чисто експериментально найду в чем проблемма. Но как это сделать пока не знаю и если подскажете то буду очень благодарен ![Улыбаюсь](/Smileys/test/smile.gif) По поводу SetThreadAffinityMask и QueueUserWorkItem я бы попробовал, но я не создавал сам потоков и где взять хендлы этих потоков не знаю. Извините, что в первом посте не уточнил, писал с помощью MFC и Visual C++ 6.0. в общем с этим буду разбираться и пробовать. Если кому-то нужно, могу выложить необходимый код кусками. Весь не могу. Начальство сказало, что секрет ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #4 : 24-02-2009 15:26 » |
|
tom4ik85, код с сокетами (CAsyncSocket я так понимаю ?) - в студию! Как раз трахался с ними, вроде разобрался, как мне кажется, неплохо. ) Вот и увидим ![Отлично](/Smileys/test/biggrin.gif) )
|
|
|
Записан
|
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #5 : 24-02-2009 19:10 » |
|
Сначала код класса, который наследует от CAsyncSocket: ...
CClient::CClient() { bIsConnected = FALSE; m_bIsThisBk = FALSE; m_nCol = m_nRow = m_nNum = 0; }
...
void CClient::OnReceive(int nErrorCode) { DWORD dwRead = 0; if(m_bIsThisBk == FALSE) dwRead = Receive(buf_bps, sizeof(buf_bps)); else dwRead = Receive(buf, sizeof(buf));
switch(dwRead) { case 0: AfxMessageBox("Error ! Receiving 0"); break; case SOCKET_ERROR: AfxMessageBox("Error ! Receiving SOCKET_ERROR"); break; default: m_pWnd->SendMessage(CL_REC, 0, (LPARAM) dwRead);
if(m_bIsThisBk == FALSE) { for(int i = 0; i<9; i++) { g_buf_bps[m_nNum][i] = buf_bps[i]; } } else { for(int i = 0; i<3; i++) { g_buf_bk[m_nCol][m_nRow][i] = buf[i]; } } break; } CAsyncSocket::OnReceive(nErrorCode); }
void CClient::OnClose(int nErrorCode) { m_pWnd->SendMessage(CL_CLOSED, 0, 0); CAsyncSocket::OnClose(nErrorCode); }
void CClient::OnConnect(int nErrorCode) { m_pWnd->SendMessage(CL_CONNECT, (WPARAM) nErrorCode, 0); CAsyncSocket::OnConnect(nErrorCode); }
...
Я повырезал не особо, на мой взгляд, выжные куски, но прикреплю .cpp и .h обоих этих классов, если нужно посмотреть внимательней. Но тут ничего особенного не делается. Использование самого сокета в классе блока ...
CBK::CBK() { m_pParent = NULL; if(m_sClient.Create() == 0) // Создаем сокет { DWORD dwError = GetLastError(); CString str; str.Format("%d on Creating Socket", dwError); if(dwError != WSAEWOULDBLOCK) AfxMessageBox(str); } m_bIsConnected = FALSE; // сбрасываем флаг подключения }
///////////////////////////////////////////////////////////////////////////// // CBK message handlers
void CBK::OnPaint() { if(m_bIsConnected == TRUE) { // Рисуем подключенный блок ... } else { // Рисуем не подключенный блок ... } }
void CBK::OnRec(WPARAM wParam, LPARAM lParam) { KillTimer(1); SetTimer(1, 500, NULL); // Сбрасываем таймер. Посылка пришла раньше чем через 500 мс ... }
void CBK::OnConnect(WPARAM wParam, LPARAM lParam) { ... if(wParam == 0) // Подключено { m_bIsConnected = TRUE;
...
SetTimer(2, 500, NULL); // Устанавливаем таймер, через который будут отсылаться тест-посылки Invalidate(); } else // Ошибка при подключении { m_bIsConnected = FALSE;
m_sClient.Close(); m_sClient.Create();
Connect(m_strAddress); Invalidate(); } }
void CBK::OnClosed(WPARAM wParam, LPARAM lParam) { m_bIsConnected = FALSE;
m_sClient.Close(); // На всякий случай закрываем сокет ... m_sClient.Create(); // ... и создаем его заново Connect(m_strAddress); // ну и подключаемся Invalidate(); }
BOOL CBK::Connect(LPCSTR addr) { // Функция для подключения. Для упрощения мне жизни
if(m_sClient.Connect(addr, 1032) == 0) { DWORD dwError = GetLastError(); CString str; str.Format("%d on Connect", GetLastError()); if(dwError != WSAEWOULDBLOCK) { return FALSE; } else { return TRUE; } } else { return TRUE; } }
void CBK::OnChanelSet(WPARAM wParam, LPARAM lParam) { // нужно отправить указания на блок
...
m_pParent->SendMessage(BK_SET_CHANEL, (m_nCol - 1)*16 + In, (m_nRow-1)*16 + Out); if(m_bIsConnected == TRUE) { buf_out[0] = 0x07 - In; buf_out[1] = 0x07 - Out; buf_out[2] = 0x01; if(m_sClient.Send(buf_out, sizeof(buf_out)) == SOCKET_ERROR) { DWORD dwError = GetLastError(); if(dwError != WSAEWOULDBLOCK) { ... OnClosed(0, 0); } else { ... } } } }
void CBK::OnChanelClean(WPARAM wParam, LPARAM lParam) { // Аналогично прошлой функции ...
if(m_bIsConnected == TRUE) { buf_out[0] = 0x07 - In; buf_out[1] = 0x07 - Out; buf_out[2] = 0x00; if(m_sClient.Send(buf_out, sizeof(buf_out)) == SOCKET_ERROR) { DWORD dwError = GetLastError(); if(dwError != WSAEWOULDBLOCK) { ... m_sClient.Close(); m_sClient.Create(); } else { ... } } } }
void CBK::SetParent(CWnd *parent) { m_pParent = parent; }
void CBK::OnTimer(UINT nIDEvent) { // Обработка таймеров
if(nIDEvent == 1) { // Посылка не дошла обратно за 500 мс
OnClosed(0, 0); KillTimer(2); KillTimer(1); CWnd::OnTimer(nIDEvent); }
else if(nIDEvent == 2) { // Отправить тест-посылку по таймеру
if(m_sClient.Send(buf_out, sizeof(buf_out)) == SOCKET_ERROR) { DWORD dwError = GetLastError(); if(dwError != WSAEWOULDBLOCK) { ... m_sClient.Close(); m_sClient.Create(); } else { ... } } } CWnd::OnTimer(nIDEvent); }
...
в общем, кому интересно посмотрите, и если сможете, то помогите пожалуйста. Я даже не знаю за что хвататься.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #6 : 25-02-2009 05:04 » |
|
tom4ik85, на первый взгляд ничего вроде тормозов не должно вызвать. 1) А вот попутно мысль - На каждом блоке запущен сервер, а программа к нему подключается, т. е. она клиент. За каждое подключение отвечает один из 20 объектов класса BK.
я бы наоборот сделал - печь была бы клиентом, а комп - сервер. Тогда комп бы просто ловил пинги да информацию. 2) Но, поскольку у тебя обратная схема (странная имхо) , то методом научного тыка определи, когда начинаются тормоза - сначала закомментируй все send. Естественно, работать всё перестанет, но ты проверь - не тогда ли уже тормоза есть ? Потом открой один сенд - проверь. Потом закрой и открой следующий. В общем, тебе , исходя из логики программы, проще разобраться, в каком порядке это сделать. Если всё это не позволит локализовать источник тормоза, тогда будем дальше думать )) 3) Ещё момент такой - при получении данных, ты отправляешь данные окнам в виде сообщений. Сообщений может быть много, а это тоже потенциальный источник тормозов. Если окно живёт всё время, пока запущена программа, я бы на твоём месте передал в сокет при его создании указатель на окно - и данные скидывал бы через указатель 4) Ещё было бы интересно измерить скорость отработка OnPaint() - поставь в начале GetTickCount и в конце, разницу тоже рисуй на окне. Хотя, там вроде нечему особо тормозить. Единственное, я бы вынес в конструктор окна m_text_tempFont->CreateFont((unsigned char) 16, pen.CreatePen(PS_SOLID, 1, m_clrPinColor); connectionPen = new CPen(PS_SOLID, 3, CLR_BLACK);
оо, а что за connectionPen = new CPen( , да ещё и без удаления ? Утечка ![Улыбаюсь](/Smileys/test/smile.gif) А new вообще зачем ?
|
|
« Последнее редактирование: 25-02-2009 05:10 от Алексей1153++ »
|
Записан
|
|
|
|
Антон (LogRus)
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #7 : 25-02-2009 06:18 » |
|
мне кажется тут всё не правильно, кроме идеи опроса серверов на предмет доступности ![Улыбаюсь](/Smileys/test/smile.gif) 1. Что за глобальные объекты без синхронизации? 2. почему нельзя клиенту передать указатель на область памяти которую надо заполнять отступление: как же я не люблю древние-оконную хрень VS 6.0 я бы сделал так: 1. Выкинуть нах обёртку ASyncSocket, использовал бы boost::asio или низкоуровневый socket 2. Заменил бы таймеры на ожидание WaitForSingleObjectEx с указанием времени ожидания 3. при получении данных подымал бы событие ожидаемое в WaitForSingleObjectEx 4. вместо 2 и 3 я бы скорее всего использовал boost::timed_wait ![Улыбаюсь](/Smileys/test/smile.gif) 5. ожидание ответа возможно делал бы в отдельном потоке через синхронный сокет. 6. если не дождались, то сокету делаем shutdown и начинаем попытки подключится вновь 7. Использовал бы синхронный сокет скорее всего. 8. логику опроса серверов отделил бы от логики GUI 9. Класс опрашивающий сервер должен получить указатель/ссылку на буфер или контейнер, а не по каким-то магическим числам определять куда бы ему данные сбросить. ну и + замечания алексея касательно GUI, но не пункт 1 ![Улыбаюсь](/Smileys/test/smile.gif) идея когда управляющий интерфейс является клиентом является идеологически правильной, представим, что быдет, если воплотить идею Алексея и дополнить это тест-кейсом "смена имени и ip управляющего интерфейса"
|
|
|
Записан
|
Странно всё это....
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #8 : 25-02-2009 06:57 » |
|
LogRus, ну начинать гон на VC и онка не нужно, это всё рабочее ) CAsyncSocket работает прекрасно (у меня сеть на 50 клиентов). с таймерами - тут да, я бы если и сделал таймер, то один на все сокеты - тактировал бы просто насчёт идея когда управляющий интерфейс является клиентом является идеологически правильной
не понимаю, чем неправильно то, что печь должна подключается к программе ? Ведь программа должна являться центром организации всей системы , и , опять же, избавляемся от опроса, а просто пассивно ждём пинга от печи. Или пакеты с данными
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #9 : 25-02-2009 07:58 » |
|
теперь перенесём это в другую плоскость: для того, что бы управлять свом веб-сервером, я должен прописать ему мой динамический IP и он будет ломится в мою систему управления им самим ![Улыбаюсь](/Smileys/test/smile.gif) бугага 1. я гоню не на весь VC, а на конкретную инкарнацию ![Улыбаюсь](/Smileys/test/smile.gif) 2. а у меня прекрасно работает socket ![Улыбаюсь](/Smileys/test/smile.gif) 3. общий таймер я бы не стал делать, мне кажется это, как-то коряво с точки зрения ООП, да и таймеры это коряво, ожидание события вот это круто ![Улыбаюсь](/Smileys/test/smile.gif) , вот так просто не обосновано, круто и всё тут. На самом деле это для меня более прозрачно, т.е. я оправил данные и сразу завис на ожидании в этой же функции, а не предполагаю, что кто-то, когда-то сгенерирует 2 разрозненных события OnTimer и OnReceive В любом случае, это всё только моё восприятие конкретной задачи и оно не претендует на истину в последней инстанции.
|
|
|
Записан
|
Странно всё это....
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #10 : 25-02-2009 08:11 » ![new](/Themes/VU3/images/english/new.gif) |
|
моё на истину тоже не претендует, моё - на практику. зачем сервер будет сам к себе обращаться ? Непонимяу. Кроме того - порежь запрос от самого себя, если уж такое может у тебя приключиться. CAsyncSocket - это SOCKET class CAsyncSocket : public CObject { ..... // Attributes public: SOCKET m_hSocket; ....
и набор функций, которые. Ничего страшного ![Улыбаюсь](/Smileys/test/smile.gif) про таймер - не всё сделаешь сообщениями, иногда без таймера не обойтись. Например, в случае, когда сервер - это печь и Томчик хочет опрашивать клиентом сервера. (Бедному клиенту надо постоянно подключаться и отключаться ![Жаль](/Smileys/test/frown.gif) ) 2 разрозненных события OnTimer и OnReceive
так не будет: 1) если печь-сервер, а программа-клиент, то OnTimer 2) если печь-клиент, а программа-сервер, то OnReceive
|
|
|
Записан
|
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #11 : 25-02-2009 09:44 » |
|
Спасибо за ответы ![Улыбаюсь](/Smileys/test/smile.gif) Попробую определить где начинаются тормоза, но скорее всего в соккетах, т.к. запуская программу на машине, не подключенной к системе нет ни загрузки процессоров ни тормозов. Все начинается после подключения. С указателем на окно в сокете попробую. Может что-то и даст ощутимое, но там других сообщений я сам бросаю намного больше, так что не думаю что это так критично. Но попробую. По поводу OnPaint() посмотрю. Мне самому интересно и я долго решал с ним какую-то проблемму. Уже не помню что именно, но у меня через минуту где-то перестал создаваться контекст рисования временный. Т.е. я создавал временный, там все рисовал, а потом уже переносил все это на экран, а то тормозила отрисовка. Этот метод мне подсказали на этом форуме давно, если не ошибаюсь, именно Алексей1153++. За что ему отдельное спасибо ![Улыбаюсь](/Smileys/test/smile.gif) И пересмотрю и поубираю такого рода утечки, если айду по тексту ![Улыбаюсь](/Smileys/test/smile.gif) LogRus-у Может все и неправильно, я в этом практически не сомневался, но на работе кроме меня программирования все боятся, а мне интересно было, поэтому начал писать. До этого был опыт программирования на "Робике" - такая приставка к телевизору, которая basic понимает ![Улыбаюсь](/Smileys/test/smile.gif) По остальным предложениям. Я пробовал это сделать на синхронном сокете, но сильно запутался с потоками, а без потоков не работало как нужно. boost::timed_wait и boost::asio мне не знакомы и врядли смогу быстро подружиться, а программу заставить работать нужно побыстрее. Я вообще старался отделить логику сокетов и графики ![Улыбаюсь](/Smileys/test/smile.gif) Наверное, не очень получилось ![Улыбаюсь](/Smileys/test/smile.gif) По поводу синхронизации глобальных переменных даже как-то не задумывался. Обязательно исправлю, т.к., мне кажется, очень вероятная причина глюков. Сначала там все было без глобальных переменных, и сейчас не вспомню зачем их ввел вообще. Посмотрю и либо, если получится, синхронизирую, либо сделаю без них. Еще раз спасибо большое за ответы ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #12 : 25-02-2009 10:13 » |
|
у меня в дополнительных потоках необходимость возникла только при отправке больших объёмов данных ) То есть, когда надо большой блок перекинуть - запускаю поток, в который передаю массив, поток кидает через Send порциями данные. Если возвращается -1 , и ошибка - WSAEWOULDBLOCK, жду 100мс и снова пробую. Основной поток не тормозит при этом
|
|
|
Записан
|
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #13 : 25-02-2009 12:17 » |
|
Сейчас расскажу как пробовал я. Например, есть 2 блока подключеных. Использую синхронный сокет и пытаюсь отправлять постоянно одному и другому информацию. Если первый отключился, то на время ожидания в WaitForSingleObject программа виснет. Если таких блока будет 2-5, то ничего страшного, а система рассчитана на 272 блока и если 10 из них перехотят отвечать (свич сгорел), то получатся значительные задержки. Еще раз повторюсь, что первая программа, поэтому может неправильно понимаю суть процессов, но с синхронным точно пробовал и интересно тогда было именно отключение неожиданное одного из блоков, потому как прописано в ТЗ. наверное я что-то недопонимаю, ра у всех работает, а у меня что-то тормозит и виснет ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #14 : 25-02-2009 12:42 » |
|
tom4ik85, может, причина не в сокете вовсе ? Вот если бы ты вот точно определил, когда зависоны происходят...
|
|
|
Записан
|
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #15 : 25-02-2009 12:54 » |
|
Я запускаю программу, когда она просто не может подключится куда-то. Сетка есть, но блоков, на которых сервера стоят нет. Она вообще не тормозит и ничего не делает ![Улыбаюсь](/Smileys/test/smile.gif) Возможность проверить с сендами будет только на выходных. Спасибо за помощь. Буду пробовать все вышесказанное, но если вдруг кого-то осенит в чем может быть причина, то пожалуйста пишите. Дело в том, что сейчас она работает на 1-ядерных и на 2-хядерных с отключенным 2-ым ядром. Именно это мне показалось очень странным, и вообще я долго искал причину тормозов, пока не увидел что именно с ядрами проблема ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #16 : 25-02-2009 13:14 » |
|
дык ждать надо в отдельном потоке.
|
|
|
Записан
|
Странно всё это....
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #17 : 25-02-2009 13:24 » |
|
Я догадываюсь, что ждать нужно в отдельном потоке, чтоб не тормозить программу, но с потоками пытался подружиться - не получилось. Я там чего-то не понимаю. Вернее вроде все понятно, но реализовать не могу. Если бы был рядом человек, который на пальцах рассказал бы на примере, может и понял бы. А так пробовал и как собака. Понимать понимаю, а сделать не могу ![Жаль](/Smileys/test/frown.gif)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #18 : 25-02-2009 17:03 » |
|
tom4ik85, без паники ![Улыбаюсь](/Smileys/test/smile.gif) 1) исправь работу с объектами GUI , уточни насчёт того new (а он там вообще нафиг не нужен) 2) сообщения к окнам замени на работу через указатели 3) прикрепи исправленный код (вернее - разрешённую часть ![Улыбаюсь](/Smileys/test/smile.gif) ) ещё попробуй выполнить программу вообще с пустым OnPaint/ мысль насчёт потоков: с одним ядром не тормозит, с двумя тормозит. Проверь, есть ли тормоза , когда 2 ядра, а подключение всего одно. Потом с двумя подключениями. Когда тормоза появятся ?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #19 : 26-02-2009 04:49 » |
|
я давал ссылку. почитайте, я же не просто так её дал ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
Странно всё это....
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #20 : 26-02-2009 15:19 » |
|
Я читал, но не все понял. Нужно со словарем почитать, а словарь дома. Хватит ли мне для синхронизации доступа к глобальным переменным использования критических секций? Насколько я понял должно хватить. Т.е. я просто все операции с глобальными переменными заключу в EnterCriticalSection() LeaveCriticalSection().
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #21 : 26-02-2009 17:50 » |
|
tom4ik85, ктритической секции достаточно, если внутри одного процесса всё происходит CCriticalSection g_crisec1;
...
if(g_crisec1.Lock(10)) { __try { работаем с переменными, долго тут задерживаться не стОит, всё как можно быстрее } __finally { //сюда попадём в любом случае g_crisec1.Unlock(); } }
|
|
|
Записан
|
|
|
|
tom4ik85
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #22 : 26-02-2009 19:37 » |
|
Спасибо. Попробую. Долго там задерживаться не получится, так как там чтение/запись в буфер. Это я так понял класс из MFC. Я просто видел пример на EnterCriticalSection() LeaveCriticalSection(). Там еще нужна инициализиция этой переменной. А здесь нет? Или она в конструкторе CCriticalSection должна быть? В любом случае, спасибо ![Улыбаюсь](/Smileys/test/smile.gif)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
![](/Themes/VU3/images/post/xx.gif) |
« Ответ #23 : 27-02-2009 05:16 » |
|
CCriticalSection g_crisec1; - это глобальная переменная (не обязательно совсем глобальная, а , например, член класса, внутри которого используется синхронизация. Если в нескольких классах - то передавать туда указатели, либо сделать совсем глобальной )) )
инициализировать не надо, конструктор без параметров. В принципе, можно обойтись и без __try __finally , если ты уверен, что после Lock ты не забудешь вызвать Unlock
Ну а можешь обернуть крисек, чтобы в деструкторе обёртки Unlock вызвался автоматом, если был вызвал Lock
|
|
|
Записан
|
|
|
|
|