BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam) { chSETDLGICONS(hWnd, IDI_QUEUE); g_hWnd = hWnd; // Used by client/server threads to show status // Prepare the SRWLock to be used InitializeSRWLock(&g_srwLock); // Prepare the condition variables to be used InitializeConditionVariable(&g_cvReadyToConsume); InitializeConditionVariable(&g_cvReadyToProduce); // Will be set to TRUE in order to end threads g_fShutdown = FALSE; // Create the writer threads DWORD dwThreadID; for (int x = 0; x < 4; x++) g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL, 0, WriterThread, (PVOID) (INT_PTR) x, 0, &dwThreadID); // Create the reader threads for (int x = 0; x < 2; x++) g_hThreads[g_nNumThreads++] = chBEGINTHREADEX(NULL, 0, ReaderThread, (PVOID) (INT_PTR) x, 0, &dwThreadID); return(TRUE); }
void CDbControllerTimer::Create( void ) { DWORD dwThreadId = 0; m_hCloseTick = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hTickThread = chBEGINTHREADEX( NULL, 0, _Tick, (LPVOID)this, 0, &dwThreadId ); ASSERT( m_hCloseTick ); ASSERT( m_hTickThread ); }
BOOL CEnvironment::CreateWorkers( void ) { DWORD dwThreadId; m_hCloseWorker = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hWorker = chBEGINTHREADEX( NULL, 0, _Worker, this, 0, &dwThreadId ); if( m_hWorker == NULL ) return FALSE; return TRUE; }
bool base_thread::CreateThread( void * psa, unsigned cbStatck, PTHREAD_START pfn, void * param, unsigned fdwCreate ) { // m_param.m_arg = param; if( m_hMsgEvent == NULL ) m_hMsgEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ResetEvent( m_hMsgEvent ); ResetEvent( m_hEvent ); m_hThread = chBEGINTHREADEX( psa, cbStatck, pfn, param, fdwCreate, &m_dwThreadID ); if( m_hThread == NULL ) return false; return true; }
BOOL CDbController::CreateDbHandler( DWORD dwMilliseconds ) { m_hIocp = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 ); if( !m_hIocp ) return FALSE; DWORD dwThreadId; m_hDbHndlr = chBEGINTHREADEX( NULL, 0, _DbHandler, (LPVOID)this, 0, &dwThreadId ); if( !m_hDbHndlr ) { ::CloseHandle( m_hIocp ); return FALSE; } SetTimer( dwMilliseconds ); return TRUE; }
VOID FirstFunc(BOOL fLocal, COptex& optex) { optex.Enter(); // Gain ownership of the optex // Since this thread owns the optex, we should be able to get it again chVERIFY(optex.TryEnter()); HANDLE hOtherThread = NULL; if (fLocal) { // Spawn a secondary thread for testing purposes (pass it the optex) DWORD dwThreadId; hOtherThread = chBEGINTHREADEX(NULL, 0, SecondFunc, (PVOID) &optex, 0, &dwThreadId); } else { // Spawn a secondary process for testing purposes STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; TCHAR szPath[MAX_PATH]; GetModuleFileName(NULL, szPath, chDIMOF(szPath)); CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); hOtherThread = pi.hProcess; CloseHandle(pi.hThread); } // Wait for the second thread to own the optex chMB("Primary: Hit OK to give optex to secondary"); // Let the second thread gain ownership of the optex optex.Leave(); optex.Leave(); // Wait for the second thread to own the optex chMB("Primary: Hit OK to wait for the optex\n(Dismiss me 1st)"); optex.Enter(); // Try to gain ownership back WaitForSingleObject(hOtherThread, INFINITE); CloseHandle(hOtherThread); optex.Leave(); }
BOOL CDbManager::CreateDbWorkers() { s_hHandle = CreateEvent( NULL, FALSE, FALSE, NULL ); for( int i = 0; i < DEFAULT_DB_WORKER_THREAD_NUM; i++ ) { m_hIOCP[i] = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 ); ASSERT( m_hIOCP[i] ); HANDLE hThread = chBEGINTHREADEX( NULL, 0, DbWorkerThread, (LPVOID)i, 0, NULL ); ASSERT( hThread ); m_hDbWorkerThreadTerminate[i] = hThread; if( WaitForSingleObject( s_hHandle, SEC( 10 ) ) == WAIT_TIMEOUT ) { OutputDebugString( "COLLECTIONSERVER.EXE\t// TIMEOUT\t// ODBC" ); return FALSE; } } CloseHandle( s_hHandle ); return TRUE; }
void Dlg_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) { switch (id) { case IDCANCEL: EndDialog(hWnd, id); break; case IDC_BTN_STOP: { // StopProcessing can't be called from the UI thread // or a deadlock will occur: SendMessage() is used // to fill up the listboxes // --> Another thread is required DWORD dwThreadID; CloseHandle(chBEGINTHREADEX(NULL, 0, StoppingThread, NULL, 0, &dwThreadID)); // This button can't be pushed twice Button_Enable(hWndCtl, FALSE); } break; } }
int _tmain(int argc, _TCHAR* argv[]) { if(argc < 2) { _tprintf(TEXT("PI <number-of-threads> <time>\n\n")); return -1; } _tsetlocale( LC_ALL, TEXT("portuguese_portugal") ); //ler do standart output o numero de tarefas a criar // DWORD NumThreads = _wtoi(argv[1]); DWORD NumThreads = 5; //ler numero de pontos a criar // DWORD Pontos = _wtoi(argv[2]); DWORD Pontos = 5000000; _tprintf( TEXT("Tarefas: %d , Pontos: %d\n"), NumThreads, Pontos ); DWORD NumPointForThread = NumThreads/Pontos; HANDLE* hThreads = (HANDLE*)calloc(NumThreads,sizeof(HANDLE)); DWORD* idThreads = (DWORD *)calloc(NumThreads,sizeof(DWORD)); int numPointAndId[2]; for(DWORD i = 0; i < NumThreads; ++i) { numPointAndId[0] = NumPointForThread; numPointAndId[1] = &idThreads[i]; hThreads[i] = chBEGINTHREADEX(NULL, 0, FunctionOfThreads, (LPVOID) numPointAndId, NULL, &idThreads[i] ); } _tprintf( TEXT("Aguarde pela terminação das threads.\n") ); WaitForMultipleObjects( NumThreads, hThreads, TRUE, INFINITE ); _tprintf( TEXT("Fechar os HANDLES das tarefas.\n") ); DWORD numOfPointsInCircle = 0; for (DWORD i=0; i<NumThreads; ++i) { DWORD in = 0; GetExitCodeThread(hThreads[i],&in); CloseHandle(hThreads[i]); numOfPointsInCircle =+ in; } _tprintf( TEXT("A percentagem de pontos dentro da circunferencia foram:\n%d"), (numOfPointsInCircle/(float)Pontos)*100 ); _tprintf( TEXT("[main] Função principal a terminar.\nPrima uma tecla para continuar.\n") ); _gettch(); free(idThreads); free(hThreads); return 0; }
BOOL CRunObject::Init( void ) { if( LoadAIScript() == FALSE ) return FALSE; // m_hClose = CreateEvent( NULL, FALSE, FALSE, NULL ); DWORD dwThreadId; m_hRunObject = chBEGINTHREADEX( NULL, 0, _Run, (LPVOID)this, 0, &dwThreadId ); // /* #ifdef __GIFTBOX0213 if( !CDPAccountClient::GetInstance()->ConnectToServer( s_szAccountAddr, PN_ACCOUNTSRVR_2, TRUE ) ) { OutputDebugString( "Can't connect to account server." ); return FALSE; } CGiftboxMan::GetInstance()->Upload( CDPAccountClient::GetInstance() ); #endif // __GIFTBOX0213 */ if( !g_DPSrvr.StartServer( (u_short)( g_uKey + PN_WORLDSRVR ), TRUE ) ) { OutputDebugString( "Can't start server." ); return FALSE; } if( !g_DPCoreClient.Run( g_szCoreAddr, PN_CORESRVR + 0, g_uKey ) ) { OutputDebugString( "Can't connect to core server." ); return FALSE; } if( !g_dpDBClient.ConnectToServer( g_szDBAddr, PN_DBSRVR_1, TRUE ) ) { OutputDebugString( "Can't connect to database server." ); return FALSE; } if ( g_eLocal.GetState( ENABLE_GUILD_INVENTORY ) ) g_dpDBClient.SendQueryGuildBank(); if( g_eLocal.GetState( EVE_WORMON ) ) g_dpDBClient.SendQueryGuildQuest(); #if __VER >= 13 // __RAINBOW_RACE if( g_eLocal.GetState( EVE_RAINBOWRACE ) ) g_dpDBClient.SendRainbowRaceReqLoad(); #endif // __RAINBOW_RACE #ifdef __INVALID_LOGIN_0320 g_dpDBClient.CalluspXXXMultiServer( g_uIdofMulti, NULL ); #else // __INVALID_LOGIN_0320 g_dpDBClient.CalluspXXXMultiServer( g_uIdofMulti, 0 ); #endif // __INVALID_LOGIN_0320 if( !CXMasEvent::GetInstance()->LoadScript( "spevent.txt" ) ) { OutputDebugString( "can't read spevent.txt" ); return FALSE; } if( g_eLocal.GetState( EVE_SCHOOL ) ) { #ifdef __IDC if( !CEveSchool::GetInstance()->LoadPos( "..\\script\\school.txt" ) ) // #else // __IDC if( !CEveSchool::GetInstance()->LoadPos( "school.txt" ) ) #endif // __IDC { OutputDebugString( "school.txt not found" ); return FALSE; } } if( g_eLocal.GetState( EVE_GUILDCOMBAT ) && !g_GuildCombatMng.LoadScript( "GuildCombat.txt" ) ) { OutputDebugString( "GuildCombat.txt not found" ); return FALSE; } #if __VER >= 12 // __ITEMCREATEMON_S0602 #if __VER < 12 // __NEW_ITEMCREATEMON_SERVER if( !g_CreateMonster.LoadScript( "CreateMonster.txt" ) ) { OutputDebugString( "CreateMonster.txt Not Found!" ); return FALSE; } #endif // __NEW_ITEMCREATEMON_SERVER #endif // __ITEMCREATEMON_S0602 return TRUE; }
int start_server (int argc, char *argv[]) { int i; int threadCount = 0; int thread_id; HANDLE g_hThread[MAX_THREAD]; char doers_number[MAXDOER][SPACE_FOR_THREAD_ID]; char movers_number[MAXMOVER][SPACE_FOR_THREAD_ID]; #ifdef INFORMIX MI_CONNECTION_INFO conn_info; // This works around a bug in Informix's isqlt09a.dll that causes memory // access violation when our program exits. memset (&conn_info, '\0', sizeof (conn_info)); mi_server_connect (&conn_info); #endif // Don't let the user start the middleware server as a standalone program. // Check whether the argument matches the magic string. if ((argc != 2) || (stricmp(argv[1], SERVER_MAGIC_STR) != 0)) { puts("Vigilert Middleware Server cannot be started as a standalone program."); puts("Start the Velara Vigilert service.\n"); Sleep (4000); exit(EXIT_FAILURE); } // Assign IDs to the multiple movers and doers for (i = 0; i < MAXDOER; i++) { sprintf (doers_number[i], "%d", i + 1); } for (i = 0; i < MAXMOVER; i++) { sprintf (movers_number[i], "%d", i + 1); } /* Initialize the global variables */ num_doer = 0; num_mover = 0; g_fTerminate = FALSE; num_doers_accessing_global_SPI = 0; puts ("\n.:. Vigilert Server .:."); // Save the memory state so we can diff against it in vl_gather_stats. _CrtMemCheckpoint (&s1); // Initialize the mutexes InitializeCriticalSection(&suspend_mutex); InitializeCriticalSection(&mover_cleaner_mutex); InitializeCriticalSection(&doer_num_mutex); InitializeCriticalSection(&mover_num_mutex); InitializeCriticalSection(&num_doers_accessing_global_SPI_mutex); InitializeCriticalSection(&Global_SPI_mutex); #ifdef _MIDDLE init_named_mem(); #endif load_keys(); #ifdef _MIDDLE InitializeCriticalSection(&logwrite_mutex); InitializeCriticalSection(&begin_udr_mutex); tm_init_conn_pool(); #endif // Initialize the semaphores that wakeup the movers and the doers // Doers can be woken up by doer dispatcher, mover (that moves the database tokens // to the database task queue) and the TCP-IP server thread that builds and moves the stream // tokens to the stream task queue. wakeup_doer_by_doer_dispatcher_sem = CreateSemaphore(NULL, 0, MAXDOER, NULL); // Semaphore for doer-dispatcher wakeup_doer_by_mover_sem = CreateSemaphore(NULL, 0, MAXDOER, NULL); // Semaphore for mover wakeup_doer_by_tcpip_server_sem = CreateSemaphore(NULL, 0, MAXDOER, NULL); // Semahpore for TCP-IP server // Mover can be wpken up by mover dispatcher. wakeup_mover_by_mover_dispatcher_sem = CreateSemaphore(NULL, 0, MAXMOVER, NULL); // Semaphore for mover-dispatcher // Initialize the array of semaphore handles that can wake up the doers wakeup_doer_array[0] = wakeup_doer_by_doer_dispatcher_sem; wakeup_doer_array[1] = wakeup_doer_by_mover_sem; wakeup_doer_array[2] = wakeup_doer_by_tcpip_server_sem; // Initialize the event variable to say whether a command execute thread is waiting to access global SPI. command_execute_waiting_event = CreateEvent(NULL, TRUE, TRUE, NULL); /* start threads */ g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, wait_end, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, mover_dispatcher, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, doer_dispatcher, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, TCPIPserver, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, cleaner, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; #ifdef _DEBUG g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, GatherStatsServer, NULL, CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; #endif for (i = 0; i < MAXDOER; i++) { g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, doer,(LPVOID)doers_number[i], CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; } for (i = 0; i < MAXMOVER; i++) { g_hThread[threadCount] = chBEGINTHREADEX(NULL, 0, mover,(LPVOID)movers_number[i], CREATE_SUSPENDED, &thread_id); tm_associate_thread_id_to_connection(threadCount, thread_id); threadCount++; } // Before starting the various threads, let the main thread run the initializing routine // to initialize all main memory data structures tm_associate_thread_id_to_connection(threadCount, tm_get_thread_id()); tman_init(); // Resume the various suspended threads one by one for (i = 0; i < threadCount; i++) { int result; result = ResumeThread(g_hThread[i]); if (result == -1) { #ifdef _MIDDLE printf ("Error: unable to start thread %d.\n", tm_own_connpool_1[i].thread_id); #endif exit (EXIT_FAILURE); } } // Wait for all the currently active threads to die or terminate before performing the cleanup // of all main memory objects and exiting the middleware server WaitForMultipleObjects(threadCount, g_hThread, TRUE, INFINITE); for (i = 0; i< threadCount; i++) CloseHandle(g_hThread[i]); DeleteCriticalSection(&mover_num_mutex); DeleteCriticalSection(&doer_num_mutex); DeleteCriticalSection(&mover_cleaner_mutex); DeleteCriticalSection(&suspend_mutex); DeleteCriticalSection(&num_doers_accessing_global_SPI_mutex); DeleteCriticalSection(&Global_SPI_mutex); CloseHandle(wakeup_mover_by_mover_dispatcher_sem); CloseHandle(wakeup_doer_by_doer_dispatcher_sem); CloseHandle(wakeup_doer_by_tcpip_server_sem); CloseHandle(wakeup_doer_by_mover_sem); CloseHandle(command_execute_waiting_event); #ifdef _MIDDLE { tm_close_conn_pool(); close_named_mem(); DeleteCriticalSection(&begin_udr_mutex); DeleteCriticalSection(&logwrite_mutex); socket_shutdown(); } #endif puts ("Vigilert run complete."); return EXIT_SUCCESS; }
int main(int argc, char** argv) { /* int outlen = 0; Compressor::lzo_encode(buffer, strlen(buffer) + 1, b2, outlen); int out3; Compressor::lzo_decode(b2, outlen, b3, out3); puts(b3); */ init_fptable(); Log::init("game_client.log"); if(argc == 2) { printf("start game: %s\n", argv[1]); cc.load_port(1); dic = new CommonNet(2, 1); } else if(argc == 3) { printf("start game: %s\n", argv[1]); use_server_style = true; game_name = string(argv[1]); cc.load_port(1); dic = new CommonNet(2, 1); } else if(argc == 4) { printf("start game: %s\n", argv[1]); use_server_style = true; game_name = string(argv[1]); int c_id = atoi(argv[3]); if(c_id > 1) { client_render = false; } cc.load_port(c_id); dic = new CommonNet(2, c_id); } else { usage(); return 0; } cc.init(); // input client connect to the server dic->ConnectServer(100); cc.send_raw_buffer(string(argv[1])); // initial the section InitializeCriticalSection(&main_section); p_main_section = &main_section; // begin the input thread DWORD dwThreadId; #ifdef USE_CLIENT_INPUT HANDLE hThreadInput = chBEGINTHREADEX(NULL, 0, InputThread, dic, 0, &dwThreadId); #endif MSG xmsg = {0}; while(xmsg.message != WM_QUIT) { if(PeekMessage(&xmsg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&xmsg); DispatchMessage(&xmsg); } else { cc.take_command(op_code, obj_id); Log::log("op_code=%d, obj_id=%d\n", op_code, obj_id); if(op_code >= 0 && op_code < MaxSizeUntilNow_Opcode) { if(client_render) (*(funcs[op_code].func))(); } else { if(op_code == MaxSizeUntilNow_Opcode) { Log::slog("game_client exit normally."); } else { Log::slog("game client exit, unexpected op_code"); } break; } } } EnterCriticalSection(p_main_section); main_thread_running = false; LeaveCriticalSection(p_main_section); cc.~CommandClient(); dic->~CommonNet(); return 0; }
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { // Obtain the user's settings from the dialog box controls. TCHAR szExpression[100]; ComboBox_GetText(GetDlgItem(hwnd, IDC_EXPRESSION), szExpression, sizeof(szExpression) / sizeof(szExpression[0])); int nObjects = GetDlgItemInt(hwnd, IDC_NUMOBJS, NULL, FALSE); switch (id) { case IDCANCEL: EndDialog(hwnd, id); break; case IDC_OBJLIST: switch (codeNotify) { case LBN_SELCHANGE: // An item changed state, reset all items and set the selected ones. for (int n = 0; n < nObjects; n++) ResetEvent(g_ahObjs[n]); for (n = 0; n < nObjects; n++) { if (ListBox_GetSel(GetDlgItem(hwnd, IDC_OBJLIST), n)) SetEvent(g_ahObjs[n]); } break; } break; case IDOK: // Prevent the user from changing values while the test is running SetFocus(GetDlgItem(hwnd, IDC_OBJLIST)); EnableWindow(GetDlgItem(hwnd, IDC_NUMOBJS), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_TIMEOUT), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_EXPRESSION), FALSE); EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); // Notify the user that the test is running SetDlgItemText(hwnd, IDC_RESULT, TEXT("Waiting...")); // Create all of the desired kernel objects ZeroMemory(g_ahObjs, sizeof(g_ahObjs)); g_awfme.m_nExpObjects = 0; ZeroMemory(g_awfme.m_ahExpObjs, sizeof(g_awfme.m_ahExpObjs)); g_awfme.m_hwnd = hwnd; g_awfme.m_dwMilliseconds = GetDlgItemInt(hwnd, IDC_TIMEOUT, NULL, FALSE); ListBox_ResetContent(GetDlgItem(hwnd, IDC_OBJLIST)); for (int n = 0; n < nObjects; n++) { TCHAR szBuf[20]; g_ahObjs[n] = CreateEvent(NULL, FALSE, FALSE, NULL); wsprintf(szBuf, TEXT(" %d"), n + 1); ListBox_AddString(GetDlgItem(hwnd, IDC_OBJLIST), &szBuf[lstrlen(szBuf) - 3]); } PTSTR p = _tcstok(szExpression, TEXT(" ")); while (p != NULL) { g_awfme.m_ahExpObjs[g_awfme.m_nExpObjects++] = (*p == TEXT('|')) ? NULL : g_ahObjs[_ttoi(p) - 1]; p = _tcstok(NULL, TEXT(" ")); } DWORD dwThreadId; CloseHandle(chBEGINTHREADEX(NULL, 0, AsyncWaitForMultipleExpressions, &g_awfme, 0, &dwThreadId)); break; } }
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) { /* Check if we are not already associated with a job. * If this is the case, there is no way to switch to * another job. */ BOOL bInJob = FALSE; IsProcessInJob(GetCurrentProcess(), NULL, &bInJob); if (bInJob) { MessageBox( NULL, TEXT("Process already in a job"), TEXT(""), MB_ICONINFORMATION | MB_OK); return(-1); } /* Create the completion port that receives job notifications * Creates an input/output (I/O) completion port * and associates it with a specified file handle, * or creates an I/O completion port that is not * yet associated with a file handle, allowing association at a later time. * * Associating an instance of an opened file handle with an I/O completion * port allows a process to receive notification of the completion * of asynchronous I/O operations involving that file handle. * * FileHandle [in] * An open file handle or INVALID_HANDLE_VALUE. * The handle must be to an object that supports overlapped I/O. * If a handle is provided, it has to have been opened * for overlapped I/O completion. * For example, you must specify the FILE_FLAG_OVERLAPPED flag * when using the CreateFile function to obtain the handle. * * If INVALID_HANDLE_VALUE is specified, * the function creates an I/O completion port without associating it * with a file handle. In this case, the ExistingCompletionPort parameter * must be NULL and the CompletionKey parameter is ignored. * * ExistingCompletionPort [in, optional] * A handle to an existing I/O completion port or NULL. * If this parameter is NULL, the function creates a new I/O completion port and, * if the FileHandle parameter is valid, associates it with the new I/O completion port. * Otherwise no file handle association occurs. * The function returns the handle to the new I/O completion port if successful. * * */ g_hIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0); /* Create a thread that waits on the completion port */ g_hThreadIOCP = chBEGINTHREADEX( NULL, 0, JobNotify, NULL, 0, NULL); /* Create the job object */ g_job.Create(NULL, TEXT("JobLab")); g_job.SetEndOfJobInfo(JOB_OBJECT_POST_AT_END_OF_JOB); g_job.AssociateCompletionPort(g_hIOCP, COMPKEY_JOBOBJECT); DialogBox(hinstExe, MAKEINTRESOURCE(IDD_JOBLAB), NULL, Dlg_Proc); /* Post a special key that tells the completion port thread to terminate * Posts an I/O completion packet to an I/O completion port. * * CompletionPort [in] * A handle to an I/O completion port to which * the I/O completion packet is to be posted. * * dwNumberOfBytesTransferred [in] * The value to be returned through the lpNumberOfBytesTransferred * parameter of the GetQueuedCompletionStatus function. * * dwCompletionKey [in] * The value to be returned through the lpCompletionKey parameter * of the GetQueuedCompletionStatus function. * * lpOverlapped [in, optional] * The value to be returned through the lpOverlapped parameter * of the GetQueuedCompletionStatus function. * */ PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_TERMINATE, NULL); /* Wait for the completion port thread to terminate */ WaitForSingleObject(g_hThreadIOCP, INFINITE); // Clean up everything properly CloseHandle(g_hIOCP); CloseHandle(g_hThreadIOCP); // NOTE: The job is closed when the g_job's destructor is called. return(0); }