1. Trang chủ
  2. » Công Nghệ Thông Tin

Thực hành hệ điều hành 3 potx

10 71 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Tirgul 3 Threads: Note – When compiling a C program that uses threads use the –lthread flag: gcc somefile.c –lthread and define the following macro: #define _REENTRANT What is the Difference between Threads and Processes? A process has its code, data, stack, open I/O, and signal table, and these are unique for every process. This causes context switching to become rather heavy. Threads on the other hand, share their data, open I/O, signal table. Only need to switch the PC, registers and the stack. What Type of Threads Exists? User-Space threads: The example of co-routines. We simulate many threads inside one “real” thread, and our application simulates the switching of threads. Allows us to define our own scheduling policy, the context switch does not involve the kernel (the OS) and the kernel does not need to manage them as well. However once some user thread performed a system call, the entire “real” thread (process) is blocked, because the kernel is not aware of the ‘fake’ threads, from her point of view, there is only one thread (process) and it should now be blocked. Kernel threads: The kernel knows these threads, and manages them, much like the managing of processes. When a process is given X time slice to run, the OS will divide this time among that process’ kernel threads. We cannot make up our own scheduling policy, and context switching is a bit more expensive since the OS is involved. Also when moving your program to run on a machine with several CPUs, each CPU can run a different thread at the same time. Some Problems with Threads: 1. Can be tricky for the none-veteran programmer (deadlocks, race conditions, sharing, locking…). 2. Defining how fork() and execvp() act when the calling process has several threads differs from OS to another. 1 Creating threads in UNIX (SOLARIS): int thr_create( void* stackBase, int stackSize, void* (*func)(void*) , void* funcArg, long flags, int* tid) - creates a new thread. If failed -1 returned, else 0 returned. The new thread will start executing the given function func which is a function that receives one argument of type voi d*. The parameter given to this function will be funcArg. The newly created thread ID will be written in tid. The given stack pointer and stack size are optional, if you wish to define exactly where the thread’s stack will be (can give 0 if u don’t want to define). Flags is also an optional parameter (don’t want -> give 0). One such flag is the THR_SUSPENDED which will cause the created thread to be immediately blocked until a thr_continue() is used to resume him. int thr_join( int tid, int* whoDied, void** status) – waits for the thread with the given tid to exit. Returns -1 if error, else 0. If the given tid is 0, it waits for any thread. If whoDied is not NULL (zero) then the TID of the dead thread will be written there. Status can be used to learn information about the dead thread – see more in man pages. thr_exit( void* stat) – terminates this thread (much like exit() terminates this process). If stat is not null, then stat is saved, and its value is given to the thread who performed join on this thread (written to join’s status parameter). int thr_self() – return this thread’s TID. Suspending and Resuming threads in UNIX (SOLARIS): int thr_suspend(int tid) and int thr_continue(int tid) – If some error occurred, a non-zero int is returned, which explains the problem (one of several constants). 0 is returned on success. thr_suspend suspends the thread with the given tid. thr_continue resumes it. Resuming a none-suspended thread does nothing. Much like suspended an already suspended thread. It should be noted that signals will not be handled by a suspended thread (signals can be stored by the system and given to the thread when it resumes). 2 Possible error return values include: ESRCH target_thread cannot be found in the current process. ECANCELED target_thread was not suspended because a subsequent thr_continue() occurred before the suspend completed. EINVAL When thr_continue() returns EINVAL, t arget_thread has died and thr_join () must be called on it to reclaim its resources. EDEADLK Suspending target_thread will cause all threads in the process to be suspended. Example: #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <stdio.h> #include <sys/errno.h> #include <pthread.h> // 3 basic lines for when dealing with threads. #include <thread.h> #define _REENTRANT typedef struct _power_data { int number; int power; } power_data; void *power(void *arguments); // declaring soon to be implemented functions. void *factorial(void *arguments); int tid1, tid2; // global vars. int main (char **argv, int argc){ power_data pd; int factD; printf("Main process started\n"); pd.number = 2; pd.power = 10; factD = 8; thr_create(NULL, NULL, power,(void *)&pd, NULL, &tid1); thr_create(NULL, NULL, factorial, (void *)&factD, THR_SUSPENDED, &tid2); printf("Created threads with ids %d and %d\n", tid1, tid2); thr_join(tid1, NULL, NULL); thr_join(tid2, NULL, NULL); printf("Main process finished now\n"); } 3 void* power(void *arguments){ power_data *pd = (power_data *)arguments; int base = pd->number; long result = base; int i, status; int rc_s, rc_c; for (i=1; i < pd->power ; i++) { result = result * base; printf("Iteration #%d of power calculation\n", i); rc_c = thr_continue(tid2); if (rc_c == 0) rc_s = thr_suspend(tid1); else { if (rc_c == EINVAL) printf("Other thread has finished already\n"); else printf("Some other error %d\n", rc_c); } } rc_c = thr_continue(tid2); printf("%dth power of %d is %d\n", pd->power, pd->number, result); thr_exit((void *)&status); } void* factorial(void *arguments) { int *number = (int *)arguments; long result = 1; int i, status; int rc_s, rc_c; for (i=1; i<*number; i++){ result = result * i; printf("Iteration #%d of factorial calculation\n", i); rc_c = thr_continue(tid1); if (rc_c == 0) rc_s = thr_suspend(tid2); else{ if (rc_c == EINVAL) fprintf(stdout, "Other thread has finished already\n"); else fprintf(stdout, "Some other error %d\n", rc_c); } } rc_c = thr_continue(tid1); printf("Factorial of %d is %d\n", *number, result); thr_exit((void *)&status); } 4 Output: Main process started Created threads with ids 4 and 5 Iteration #1 of power calculation Iteration #1 of factorial calculation Iteration #2 of power calculation Iteration #2 of factorial calculation Iteration #3 of power calculation Iteration #3 of factorial calculation Iteration #4 of power calculation Iteration #4 of factorial calculation Iteration #5 of power calculation Iteration #5 of factorial calculation Iteration #6 of power calculation Iteration #6 of factorial calculation Iteration #7 of power calculation Iteration #7 of factorial calculation Iteration #8 of power calculation Factorial of 8 is 5040 Iteration #9 of power calculation Other thread has finished already 10th power of 2 is 1024 Main process finished now Threads in other Operating Systems: Next we will demonstrate an identical example on several platforms – Unix, Linux and Windows. In the following example two threads try to compute the same value; the first one to finish kills the other one. 5 UNIX (SOLARIS): #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <thread.h> #include <pthread.h> #define _REENTRANT int tid1, tid2; typedef struct _param { int number; int sleep_time; } param; void *nice_thread(void *arg); int main (char **argv, int argc){ int rc1, rc2; param param1, param2; param1.number = 10; param1.sleep_time = 2; rc1 = thr_create(NULL, NULL, nice_thread, (void *)&param1, NULL, &tid1); param2.number = 10; param2.sleep_time = 7; rc2 = thr_create(NULL, NULL, nice_thread, (void *)&param2, NULL, &tid2); printf("Created threads with tid 1 =%d and tid 2 =%d\n", tid1, tid2); thr_join(tid1, NULL, NULL); thr_join(tid2, NULL, NULL); } void *nice_thread(void *arg){ int i; param *args = (param *)arg; long result = 1; for (i=1; i<args->number; i++) { result = result * i; fprintf(stdout, "Current result = %d from %d\n", result, thr_self()); sleep(args->sleep_time); } if (thr_self() == tid1) { thr_kill(tid2, SIGKILL); fprintf(stdout, "Thread %d is a killer of %d\n", thr_self(), tid2); } if (thr_self() == tid2){ thr_kill(tid1, SIGKILL); fprintf(stdout, "Thread %d is a killer of %d\n", thr_self(), tid1); } printf("Final result =%d, given by thread %d\n", result, thr_self()); return NULL; } 6 LINUX (POSIX): #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> #include <sys/times.h> #define _REENTRANT pthread_t tid1, tid2; typedef struct _param { int number; int sleep_time; } param; void *nice_thread(void *arg); int main (int argc,char **argv) { int rc1, rc2; param param1, param2; param1.number = 10; param1.sleep_time = 7; rc1 = pthread_create(&tid1, NULL, nice_thread, (void *)&param1); param2.number = 10; param2.sleep_time = 2; rc2 = pthread_create(&tid2,NULL, nice_thread, (void *)&param2); printf("Created threads with tid 1 =%d and tid 2 =%d\n", tid1, tid2); pthread_join(tid1,NULL); pthread_join(tid2,NULL); } void *nice_thread(void *arg) { int i; char cmd[100]; param *args = (param *)arg; long result = 1; for (i=1; i<args->number; i++){ result = result * i; fprintf(stdout, "Current result = %d from %d\n", result, pthread_self()); sprintf (cmd, "sleep %d", args->sleep_time); system(cmd); } if (pthread_self() == tid1) { pthread_kill(tid2, SIGKILL); fprintf(stdout, "Thread %d is a killer of %d\n", pthread_self(), tid2); } if (pthread_self() == tid2) { pthread_kill(tid1, SIGKILL); fprintf(stdout, "Thread %d is a killer of %d\n", pthread_self(), tid1); } printf("Final result =%d, given by thread %d\n", result, pthread_self()); return NULL; } 7 WINDOWS )NT(: #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <windows.h> #define _REENTRANT int tid1, tid2; HANDLE rc1, rc2; typedef struct _param{ int number; int sleep_time; }param; DWORD WINAPI nice_thread(void *arg); int main (int argc,char **argv) { param param1, param2; param1.number = 10; param1.sleep_time = 7; rc1 = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE) nice_thread, (void *)&param1, 0, &tid1); param2.number = 10; param2.sleep_time = 2; rc2 = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)nice_thread, (void *)&param2, 0, &tid2); printf("Created threads with tid 1 =%d and tid 2 =%d\n", tid1, tid2); WaitForSingleObject(rc1,INFINITE); WaitForSingleObject(rc2,INFINITE); } DWORD WINAPI nice_thread(void *arg) { int i; param *args = (param *)arg; long result = 1; for (i=1; i<args->number; i++) { result = result * i; printf("Current result = %d from %d\n", result,GetCurrentThreadId()); Sleep(args->sleep_time*1000); } if (GetCurrentThreadId() == tid1) { TerminateThread(rc2,0); printf("Thread %d is a killer of %d\n",GetCurrentThreadId(), tid2); } if (GetCurrentThreadId() == tid2) { TerminateThread(rc1,0); printf("Thread %d is a killer of %d\n",GetCurrentThreadId(), tid1); } printf("Final result =%d, given by %d\n", result,GetCurrentThreadId()); return 0; } 8 Windows Fibers: Also known as lightweight threads. Fibers allow an application to schedule its own ‘threads’ execution order rather than relying on the system’s scheduler. Using fibers can make it easier to port applications that were designed to schedule their own threads. In terms of the OS, these fibers do not exist. They are all implemented completely in user mode. The OS sees only the threads (and processes). So if a fiber is running on some thread and performs an action like ExitThread(), then the thread that is running this fiber is terminated. Fibers are not preemptively scheduled. You schedule a fiber by switching to it from another fiber. The system still schedules threads to run. When a thread running fibers is preempted, its currently running fiber is preempted. The fiber runs when the thread runs. See more: http://msdn.microsoft.com/library/default.asp?url=/library/en- us/dllproc/base/about_processes_and_threads.asp Example: #include <windows.h> #include <stdio.h> // soon to be implemented functions: VOID __stdcall Fiber1Func(LPVOID lpParameter); VOID __stdcall Fiber2Func(LPVOID lpParameter); // data struct to be given to the fibers as parameters: typedef struct { DWORD dwParameter; // parameter to fiber DWORD dwNumber; // result data } FIBERDATASTRUCT, *POINTER_TO_FIBERDATASTRUCT; #define FIBER_COUNT 3 // total number of fibers (including primary) #define PRIMARY_FIBER 0 // array index to primary fiber #define FIBER1 1 // array index to read fiber #define FIBER2 2 // array index to write fiber LPVOID g_lpFiber[FIBER_COUNT]; // global array of pointers to fibers int __cdecl main(int argc,char *argv[]) { POINTER_TO_FIBERDATASTRUCT fs; // allocate storage for our fiber data structures fs = (POINTER_TO_FIBERDATASTRUCT) HeapAlloc( GetProcessHeap(), 0, sizeof(FIBERDATASTRUCT) * FIBER_COUNT); 9 // convert this thread to a fiber, to allow scheduling of other fibers g_lpFiber[PRIMARY_FIBER] = ConvertThreadToFiber(&fs[PRIMARY_FIBER]); // initialize the data structures fs[PRIMARY_FIBER].dwParameter = 0; fs[FIBER1].dwParameter = 1; fs[FIBER2].dwParameter = 3; fs[PRIMARY_FIBER].dwNumber = 0; fs[FIBER1].dwNumber = 0; fs[FIBER2].dwNumber = 0; // create the first fiber g_lpFiber[FIBER1] = CreateFiber(0, Fiber1Func, &fs[FIBER1]); // create the second fiber g_lpFiber[FIBER2]=CreateFiber(0, Fiber2Func, &fs[FIBER2]); // switch to the first fiber SwitchToFiber(g_lpFiber[FIBER1]); // We have now been scheduled again. Display results: printf("Fiber1 result == %lu number == %lu\n", fs[FIBER1].dwNumber); printf("Fiber2 result == %lu number == %lu\n", fs[FIBER2].dwNumber); // Delete the fibers DeleteFiber(g_lpFiber[FIBER1]); DeleteFiber(g_lpFiber[FIBER2]); // free allocated memory HeapFree(GetProcessHeap(), 0, fs); } VOID __stdcall Fiber1Func(LPVOID lpParameter) { POINTER_TO_FIBERDATASTRUCT fds = (POINTER_TO_FIBERDATASTRUCT)lpParameter; int i; for (i = 0;i < 4;i++ ){ // TODO: perform some calculation. printf("fiber1 printing %d\n",i); SwitchToFiber(g_lpFiber[FIBER2]); } fds->dwNumber = 2*i; // and switch to the second fiber SwitchToFiber(g_lpFiber[FIBER2]); } VOID __stdcall Fiber2Func(LPVOID lpParameter) { POINTER_TO_FIBERDATASTRUCT fds = (POINTER_TO_FIBERDATASTRUCT)lpParameter; int i; for (i = 0;i < 4;i++ ){ // TODO: perform some calculation. printf("fiber2 printing %d\n",i); SwitchToFiber(g_lpFiber[FIBER1]); } fds->dwNumber = 4*i; // and switch to the primary fiber SwitchToFiber(g_lpFiber[PRIMARY_FIBER]); } 10 . calculation Iteration #2 of power calculation Iteration #2 of factorial calculation Iteration #3 of power calculation Iteration #3 of factorial calculation Iteration #4 of power calculation Iteration #4 of factorial. <fcntl.h> #include <stdio.h> #include <sys/errno.h> #include <pthread.h> // 3 basic lines for when dealing with threads. #include <thread.h> #define _REENTRANT typedef. thr_join(tid1, NULL, NULL); thr_join(tid2, NULL, NULL); printf("Main process finished now "); } 3 void* power(void *arguments){ power_data *pd = (power_data *)arguments; int base = pd->number;

Ngày đăng: 28/07/2014, 21:21

Xem thêm: Thực hành hệ điều hành 3 potx

TỪ KHÓA LIÊN QUAN

w