/******************************************************************************/ /** @file "Pthreads/C/Ispitni zadaci/si4mps_k1_20092010_z5.c" @brief Trazenje apsolutnog maksimumam uz ispis trenutno aktuelne vrednosti. @author Nepoznat */ /******************************************************************************/ // Ovo je samo jedno od mnogih mogućih rešenja zadatka #include #include #include #include const size_t NUM_THREADS = 5; void CreateAndLoadArray(double* &p_numbers, size_t& p_count) { std::cout << "Unesite broj elemenata niza: "; std::cin >> p_count; try { p_numbers = new double[p_count]; } catch (std::bad_alloc) { p_numbers = NULL; } if (NULL != p_numbers && p_count >= NUM_THREADS) { std::cout << "Unesite elemente niza: "; for (size_t index = 0; index < p_count; index++) { std::cin >> p_numbers[index]; } } else { p_numbers = NULL; p_count = 0; } } enum ThreadsState { THREADS_NOT_STARTED, THREADS_STARTED, THREADS_FINISHED }; // promenljive koje opisuju stanje niti ThreadsState g_threadsState = THREADS_NOT_STARTED; unsigned g_activeThreadCount = NUM_THREADS; pthread_mutex_t g_threadsStateLock; pthread_cond_t g_threadsStateCond; // promenljive koje se tiču maksimuma double g_maximum; bool g_isMaximumUpdated = false; pthread_mutex_t g_maximumLock; pthread_cond_t g_maximumUpdatedCond; typedef struct thread_input_data { double *m_elements; size_t m_baseOffset; size_t m_endOffset; } ThreadInputData; void* FindMaximum(void *pData) { // sve što je uslovljeno sa PTW32_STATIC_LIB je potrebno // samo za pthreads-win32 i to samo u static linked varijanti #ifdef PTW32_STATIC_LIB pthread_win32_thread_attach_np(); { #endif // prvo sačekaj da sve niti budu stvorene i spremne za izvršavanje pthread_mutex_lock(&g_threadsStateLock); while(THREADS_STARTED != g_threadsState) { pthread_cond_wait(&g_threadsStateCond, &g_threadsStateLock); } pthread_mutex_unlock(&g_threadsStateLock); ThreadInputData *pThreadData = static_cast (pData); // napravi kopiju globalnog maksimuma, da ne bi za svako poređenje ulazio u kritičnu sekciju pthread_mutex_lock(&g_maximumLock); double maximumCopy = g_maximum; pthread_mutex_unlock(&g_maximumLock); // upoređuj redom elemente for (size_t index = pThreadData->m_baseOffset; index < pThreadData->m_endOffset; index++) { // ako je apsolutna vrednost tekućeg elementa veća od lokalne kopije maksimuma if (fabs(pThreadData->m_elements[index]) > maximumCopy) { // tek tada idi u kritičnu sekciju pthread_mutex_lock(&g_maximumLock); if (fabs(pThreadData->m_elements[index]) > g_maximum) { // po potrebi, ažuriraj globalni maksimum i obavesti glavnu nit g_maximum = pThreadData->m_elements[index]; g_isMaximumUpdated = true; pthread_cond_signal(&g_maximumUpdatedCond); } // u svakom slučaju, iskoristi ulazak u kritičnu sekciju // za ažuriranje lokalne kopije maksimuma maximumCopy = g_maximum; pthread_mutex_unlock(&g_maximumLock); // for (int index = 0; index < 1000000000; index++) index++; } } // kad završiš pretragu, smanji broj aktivnih niti za 1 pthread_mutex_lock(&g_threadsStateLock); g_activeThreadCount--; if (0 == g_activeThreadCount) { g_threadsState = THREADS_FINISHED; // Glavna nit i dalje čeka - pošto je ovo poslednja od stvorenih niti, // signaliziraj glavnoj niti da je pretraga gotova pthread_mutex_lock(&g_maximumLock); g_isMaximumUpdated = true; pthread_cond_signal(&g_maximumUpdatedCond); pthread_mutex_unlock(&g_maximumLock); } pthread_mutex_unlock(&g_threadsStateLock); // sve što je uslovljeno sa PTW32_STATIC_LIB je potrebno // samo za pthreads-win32 i to samo u static linked varijanti #ifdef PTW32_STATIC_LIB } pthread_win32_thread_detach_np(); #endif // pthread_exit(NULL); nije neophodno pošto će implicitno biti pozvano return NULL; } int main() { // sve što je uslovljeno sa PTW32_STATIC_LIB je potrebno // samo za pthreads-win32 i to samo u static linked varijanti #ifdef PTW32_STATIC_LIB pthread_win32_process_attach_np(); pthread_win32_thread_attach_np(); { #endif // niz i broj elemenata double *elements; size_t elementCount; CreateAndLoadArray(elements, elementCount); if (0 != elementCount) { pthread_mutex_init(&g_maximumLock, NULL); pthread_cond_init(&g_maximumUpdatedCond, NULL); pthread_mutex_init(&g_threadsStateLock, NULL); pthread_cond_init(&g_threadsStateCond, NULL); ThreadInputData threadData[NUM_THREADS]; pthread_t searchers[NUM_THREADS]; g_maximum = fabs(elements[0]); for (size_t index = 0; index < NUM_THREADS; index++) { threadData[index].m_elements = elements; size_t sliceSize = elementCount / NUM_THREADS; threadData[index].m_baseOffset = sliceSize * index; /* poslednja nit dobija eventualne viškove */ if (NUM_THREADS - 1 == index) { sliceSize += elementCount % NUM_THREADS; } threadData[index].m_endOffset = threadData[index].m_baseOffset + sliceSize; pthread_create(&searchers[index], NULL, FindMaximum, &threadData[index]); } // sve niti koje su možda počele sa izvršavanjem i čekaju sada mogu biti deblokirane pthread_mutex_lock(&g_threadsStateLock); g_threadsState = THREADS_STARTED; pthread_cond_broadcast(&g_threadsStateCond); // ovde nema otključavanja da neka nit ne bi bila deblokirana i možda gotova // pre nego glavna nit krene da prati promenljivu sa stanjem svih niti double lastKnownMaximum = g_maximum; // sve dok makar jedna stvorena nit još uvek radi while(THREADS_FINISHED != g_threadsState) { ThreadsState threadsState = g_threadsState; // otključavanje nakon dohvatanja vrednosti pthread_mutex_unlock(&g_threadsStateLock); pthread_mutex_lock(&g_maximumLock); while(false == g_isMaximumUpdated) { pthread_cond_wait(&g_maximumUpdatedCond, &g_maximumLock); } // ispiši novu vrednost samo je poznata // (zaštita od suvišnog ispisa, potrebna u dva slučaja: // kada je element sa indeksom 0 maksimalan i kada naiđe // "preventivni" signal zadat na kraju poslednje stvorene niti if (lastKnownMaximum != g_maximum) { std::cout << "Nova vrednost maksimuma je: " << g_maximum << std::endl; lastKnownMaximum = g_maximum; } g_isMaximumUpdated = false; pthread_mutex_unlock(&g_maximumLock); // zaključavanje pre sledeće provere stanja niti pthread_mutex_lock(&g_threadsStateLock); } pthread_mutex_unlock(&g_threadsStateLock); // ispiši konačni rezultat std::cout << "Maksimalna apsolutna vrednost je: " << g_maximum << std::endl; pthread_mutex_destroy(&g_maximumLock); pthread_mutex_destroy(&g_threadsStateLock); pthread_cond_destroy(&g_maximumUpdatedCond); pthread_cond_destroy(&g_threadsStateCond); delete [] elements; } // sve što je uslovljeno sa PTW32_STATIC_LIB je potrebno // samo za pthreads-win32 i to samo u static linked varijanti #ifdef PTW32_STATIC_LIB } pthread_win32_thread_detach_np(); pthread_win32_process_detach_np(); #endif return 0; }