υπολογισμός | μετατροπή σε λέξη | φωνητική ανάγνωση bc | number | speak
Μετατροπή κειμένου σε λέξεις | φιλτράρισμα λέξεων | ταξινόμηση | μέτρηση κοινών γραμμών | ταξινόμηση tr -cs A-Za-z '\012' | grep '^A-Za-z' | sort | uniq -c | sort -rn
int counter; process_one() { int i; i = counter; i = i + 1; counter = i; } process_two() { int i; i = counter; i = i + 1; counter = i; }
Κάθε λύση στο πρόβλημα του αμοιβαίου αποκλεισμού (mutual exclusion) μεταξύ των κρίσιμων τμημάτων πρέπει να εξασφαλίζει:
const N = 100; int queue[N]; int count; void producer(void) { int item; for (;;) { create(&item); if (count == N) sleep(); count = count + 1; queue[count - 1] = item; if (count == 1) wakeup(consumer); } } void consumer(void) { int item; for (;;) { if (count == 0) sleep(); item = queue[count - 1]; count = count - 1; if (count == N - 1) wakeup(producer); consume(&item); } }Η παραπάνω λύση έχει πρόβλημα συνθήκης ανταγωνισμού ως προς τη χρήση της μεταβλητής count.
const N = 100; semaphore mutex = 1; semaphore empty = N; semaphore full = 0; void producer(void) { int item; for (;;) { create(&item); signal(&empty); signal(&mutex); count = count + 1; queue[count - 1] = item; wait(&mutex) wait(&full); } } void consumer(void) { int item; for (;;) { signal(&full); signal(&mutex); item = queue[count - 1]; count = count - 1; wait(&mutex); wait(&empty); consume(&item); } }
Η δομή αυτή εξασφαλίζει τον αμοιβαίο αποκλεισμό κρισίμων τμημάτων. H αναστολή διεργασιών που δεν μπορούν να συνεχίσουν εξασφαλίζεται με τη χρήση των μεταβλητών συνθήκης (condition variables)
const N = 100; int queue[N]; void producer(void) { int item; message m; for (;;) { create(&item); receive(consumer, &m); build_message(item, &m); send(consumer, &m); } } void consumer(void) { int item; message m; for (i = 0; i < 100; i++) send(producer, &m); for (;;) { receive(producer, &m); extract_item(&m, &item); send(producer, &m); consume(&item); } }
void thread_function(int *parameter) { } /* Used to pass a parameter to the thread */ int parameter_value; main() { parameter = 42; _beginthread(thread_function, 0, ¶meter); }Ένα νήμα μπορεί να τερματίσει τη λειτουργία του με τη συνάρτηση _endthread.
HANDLE mutex; /* Declare semaphore variable */ mutex = CreateMutex(NULL, FALSE, NULL); /* Create semaphore */
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);
HANDLE mutex= CreateMutex(NULL, FALSE, NULL); WaitForSingleObject(mutex, INFINITE); /* Critical work starts here */ fseek(fp, desired_position, 0L ); fwrite(data, sizeof( data ), 1, fp ); /* Critical work ends here */ ReleaseMutex(mutex);
cl -D_MT /MT test.c
/* * Bounce - Creates a new thread each time the letter 'a' is typed. Each * thread bounces a happy face of a different color around the screen. All * threads are terminated when the letter 'Q' is entered. * * This program requires the multithread library. For example, compile with the * following command line: CL /MT BOUNCE.C */ #include <windows.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <conio.h> #include <process.h> const int MAX_THREADS=32; /* * getrandom returns a random number between min and max, which must be in * integer range. */ static int getrandom(int min, int max) { return ((rand() % (int)(((max) + 1) - (min))) + (min)); } void main(void); /* Thread 1: main */ void KbdFunc(void); /* Keyboard input, thread dispatch */ void BounceProc(char *MyID); /* Threads 2 to n: display */ void ClearScreen(void); /* Screen clear */ void ShutDown(void); /* Program shutdown */ void WriteTitle(int ThreadNum); /* Display title bar information */ HANDLE hConsoleOut; /* Handle to the console */ HANDLE hRunMutex; /* "Keep Running" mutex */ HANDLE hScreenMutex; /* "Screen update" mutex */ int ThreadNr; /* Number of threads started */ CONSOLE_SCREEN_BUFFER_INFO csbiInfo; /* Console information */ void main() { /* Thread One */ /* Get display screen information & clear the screen. */ hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hConsoleOut, &csbiInfo); ClearScreen(); WriteTitle(0); /* Create the mutexes and reset thread count. */ hScreenMutex = CreateMutex(NULL, FALSE, NULL); /* Cleared */ hRunMutex = CreateMutex(NULL, TRUE, NULL); /* Set */ ThreadNr = 0; /* Start waiting for keyboard input to dispatch threads or exit. */ KbdFunc(); /* All threads done. Clean up handles. */ CloseHandle(hScreenMutex); CloseHandle(hRunMutex); CloseHandle(hConsoleOut); } /* * Finish processing */ void ShutDown(void) { /* Shut down threads */ while (ThreadNr > 0) { /* Tell thread to die and record its death. */ ReleaseMutex(hRunMutex); ThreadNr--; } /* Clean up display when done */ WaitForSingleObject(hScreenMutex, INFINITE); ClearScreen(); } /* * Read an process keyboard commands */ void KbdFunc(void) { /* Dispatch and count threads. */ int KeyInfo; do { KeyInfo = _getch(); if (tolower(KeyInfo) == 'a' && ThreadNr < MAX_THREADS) { ThreadNr++; _beginthread(BounceProc, 0, &ThreadNr); WriteTitle(ThreadNr); } } while (tolower(KeyInfo) != 'q'); ShutDown(); } /* * Bounce the face around the screen. * This procedure is run by each thread. */ void BounceProc(char *MyID) { char MyCell, OldCell; WORD MyAttrib, OldAttrib; char BlankCell = 0x20; COORD Coords, Delta; COORD Old = {0, 0}; DWORD Dummy; /* Generate update increments and initial display coordinates. */ srand((unsigned) *MyID * 3); Coords.X = getrandom(0, csbiInfo.dwSize.X - 1); Coords.Y = getrandom(0, csbiInfo.dwSize.Y - 1); Delta.X = getrandom(-3, 3); Delta.Y = getrandom(-3, 3); /* Set up "happy face" & generate color attribute from thread number. */ if (*MyID > 16) MyCell = 0x01; /* outline face */ else MyCell = 0x02; /* solid face */ MyAttrib = *MyID & 0x0F;/* force black background */ do { /* Wait for display to be available, then lock it. */ WaitForSingleObject(hScreenMutex, INFINITE); /* If we still occupy the old screen position, blank it out. */ ReadConsoleOutputCharacter(hConsoleOut, &OldCell, 1, Old, &Dummy); ReadConsoleOutputAttribute(hConsoleOut, &OldAttrib, 1, Old, &Dummy); if ((OldCell == MyCell) && (OldAttrib == MyAttrib)) WriteConsoleOutputCharacter(hConsoleOut, &BlankCell, 1, Old, &Dummy); /* Draw new face, then clear screen lock */ WriteConsoleOutputCharacter(hConsoleOut, &MyCell, 1, Coords, &Dummy); WriteConsoleOutputAttribute(hConsoleOut, &MyAttrib, 1, Coords, &Dummy); ReleaseMutex(hScreenMutex); /* Increment the coordinates for next placement of the block. */ Old.X = Coords.X; Old.Y = Coords.Y; Coords.X += Delta.X; Coords.Y += Delta.Y; /* If we are about to go off the screen, reverse direction */ if (Coords.X < 0 || Coords.X >= csbiInfo.dwSize.X) { Delta.X = -Delta.X; Beep(400, 50); } if (Coords.Y < 0 || Coords.Y > csbiInfo.dwSize.Y) { Delta.Y = -Delta.Y; Beep(600, 50); } } /* Repeat while RunMutex is still taken. */ while (WaitForSingleObject(hRunMutex, 75L) == WAIT_TIMEOUT); } void WriteTitle(int ThreadNum) { char NThreadMsg[80]; sprintf(NThreadMsg, "Threads running: %02d. Press 'A' to start a thread,'Q' to quit.", ThreadNum); SetConsoleTitle(NThreadMsg); } void ClearScreen(void) { DWORD dummy; COORD Home = {0, 0}; FillConsoleOutputCharacter(hConsoleOut, ' ', csbiInfo.dwSize.X * csbiInfo.dwSize.Y, Home, &dummy); }