lecture notes 1. example 1 fgets -- get user input from standard input sscanf -- parse user input, pass alarm seconds and message into variables sleep -- have the process for a mount of time specified by argument it is a synchronous process, which means user can only set one command at a time. Only after one timer is up could user set the next timer. Commands will be accepted one by one. 2. Example two fork() - spawn off a child process after fork(), a child process almost identical (same program code, same file desciptors) with the parent is running, except that the return value is different. waitpid(-1, NULL, WNOHANG) > calling process will try to wait for the child process to terminate. > WNOHANG -- waitpis function will not suspend the execution of the calling process. > when the status of a child process is available , then return its pid it is a multi-process solution. it will fork a new process to carry out the timer work. it can allow users to set alarms without waiting for the first one to complete. however, i will have much overhead and the program itself is not very straightforward to readers. 3. Example three >first we have to define a structure, since we can only have one parameter to be passed to the thread function, which will be a pointer to the structure. >the thread function's format is: void * thread_func ( void * arg), the arg will be passed from the thread creator's pthread_create() call. >in the body of function , you have to cast the pointer to the appropriate structure type. as you can see: alarm_t *alarm = (alarm_t *) arg; > pthread_detach() detach is to tell system, when this thread complete, its resources can be recycled. otherwise, some zombie threads will retain all system resources such as memory space. detach can be done by itself, or by the caller after creating a thread. >if you want to terminate a thread, use pthread_exit(void *value_ptr), then the calling thread itself returns an exit status in value_ptr. This value is returned to a joining thread calling pthread_join(thisthread). ***Only threads created with the detachstate attribute value PTHREAD_CREATE_JOINABLE can return an exit status to pthread_join(). For the detached thread, the return value is lost.**** > remember to free unused memory spaces . this is Multi-threaded solution. better performance, easier to read. 3. Pthread functions a. pthread_t thread; it is a abstract object, it is the unique ID of a thread. b. int pthread_create( pthread_t *tid, const pthread_attr_t *attr, void *(*start)(void *), void *arg); >tid is a pointer to pthread id, pthread_create will return the id of the new thread created. >a thread id, can only be get by creator or the thread itself (by calling pthread_self). if some other threads will use it, you have to store it somewhere. >attr is the attribute of the thread being created. just let it be NULL. >start, the name of your thread function. >arg, the parameter that will be passed to the thread function. >one thing, calling thread's return from one thread will not synchronized with the scheduling of new thread. that is, a new thread may even begin running BEFORE the pthread_create returns in the caller. c. int pthread_detach( pthread_t tid); > it will not affect that thread in any way. > it is to inform the system that the thread's resource can be reclaimed when thread eventually terminate. > system resources include stacks, local variables etc. > you can set the attributes of a thread when creating, instead of using detach explicitly d. int pthread_equal( pthread_t t1, pthread_t t2); > it is no sense to say t1 is bigger or less than t2. > if t1 and t2 refer to the same thread, then return a nonzero value, otherwise 0. e. int pthread_exit( void *value_ptr); > if you want to terminate a thread, use pthread_exit(void *value_ptr), then the calling thread itself returns an exit status in value_ptr. This value is returned to a joining thread calling pthread_join(thisthread). > you can use pthread_exit to terminate the initial thread while allowing other thread running. f. int pthread_join( pthread_t tid, void **value_ptr); > if you want to know a thread's return value, or if you need to know when a thread has completed. pthread_join will help you. > it blocks the caller, > it detach the specified thread automatically. > after pthread_join, the joinee has been "detached" & can't join with it again. g. pthread_t pthread_self(void ); > will return the thread id of the calling thread itself. h. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); > pthread_mutex_t is a special form of semaphore which you may learn from the OS course. > Declare a mutex using extern or static, since more than one threads will use it. > Initialize a mutex before you use a mutex, although sometimes it works if you don't. statically, pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER or dynamically, pthread_mutex_init (& mutex, NULL); > Use NULL in the second parameter to use default attributes i. int pthread_mutex_destroy(pthread_mutex_t *mutex); > after usage, destroy the mutex that's initialized dynamically. j. int pthread_mutex_lock(pthread_mutex_t *mutex); > before try to use a shared resource, lock the mutex first. k. int pthread_mutex_unlock(pthread_mutex_t *mutex); > after using a shared resource, unlock the mutex to let other blocked threads get access to the resource. > do not try to unlock a mutex that has not been locked, it will cause undefined results. l. int pthread_mutex_trylock(pthread_mutex_t *mutex); > the function pthread_mutex_trylock() is identical to the pthread_mutex_lock() function except that if the mutex object referenced by mutex cannot be acquired after one attempt, the call returns immediately with an error. m. int pthread_cancel(pthread_t tid) >pthread_cancel() requests that thread (hereby referred to as target thread) be canceled. It allows a thread to terminate the execution of any thread in the process in a controlled manner. >The target thread's cancelability state and type determine when the cancellation takes effect. Cancellation only occurs when the target thread's cancelability state is PTHREAD_CANCEL_ENABLE. we're lucky that the default state of a thread is PTHREAS_CANCEL_ENABLE. When the target thread's cancelability state is PTHREAD_CANCEL_DISABLE, cancellation requests against the target thread are held pending and will be acted upon when cancellation is enabled. 4. C++ Wrapper why we need wrapper? because in C++, the compiler will do the following: for example, you have a thread function which is a class member function. such as the Auction object you may have: class Auction { private: char *Auction_Tile; .. public: void* Mod(void *New_Title); } actually, the compiler will change void* Mod(void *New_Title) to void* Mod(Auction * this, void *New_Title) Then, what is the problem? The problem is that it violates the parameter passing mechanism of the pthread_create() function ! (remember it?) Here comes TWO parameters while Pthread only accepts one. Here is the trick to solve this problem--Wrapper. (see test_pthread.cc) we use : struct Mywrapper { Auction * Me; char *Title; .. } and clase Auction { private: char *Auction_Tile; public: static void* Mod( void *arg) { Mywrapper *Unpack = (mywrapper *)arg; Auction * myauction = Unpack->Me; strcpy(myauction -> Auction_Title, Unpack -> Title); ... } } in the main(), you should use wrapper like this: ... Auction myauc; Mywrapper Topass; Topass -> Me = &myauc; strcpy(Topass -> Title , "This is for Bugs"); pthread_create(&tid, NULL, myauc.Mod, &Topass); ... that is, you have to pack your data into mywrapper structure, then pass this whole bundle to the thread function. 5. reentrant function and thread-saft code. see details through the URL Note: use strtok_r instead of strtok(), Some of the standard C subroutines are non-reentrant, such as the ctime and strtok subroutines. The reentrant version of the subroutines have the name of the original subroutine with a suffix _r (underscore r). When writing multi-threaded programs, the reentrant versions of subroutines should be used instead of the original version. For example, the following code fragment: token[0] = strtok(string, separators); i = 0; do { i++; token[i] = strtok(NULL, separators); } while (token[i] != NULL); should be replaced in a multi-threaded program by the following code fragment: char *pointer; ... token[0] = strtok_r(string, separators, &pointer); i = 0; do { i++; token[i] = strtok_r(NULL, separators, &pointer); } while (token[i] != NULL); 6. Objects in the assignment 1) Thread object: class Thread_Object { private: pthread_t* My_Thread; int My_Id; char* Description; public: Thread_Object(pthread_t*, int, char*); ~Thread_Object(); void Print(); int Id(); }; 2)class Thread_Manager { private: list All_Threads; int Current_Id_Counter; public: Thread_Manager(); ~Thread_Manager(); void List_Threads(); void Make_Thread(void* Func(void*), void* Data, char* Description); void Kill_Thread(int Id_To_Kill); }; 3)class Data_Object { friend class Store; private: char* Title; char* Seller int Timeleft; int BidAmount char *Bidder char* ID; public: Data_Object(char* Title, char* Seller, int Timeleft, int BidAmount,char *Bidder, char* ID); ~Data_Object(); bool operator==(Data_Object X); bool Compare_Title(char* to_compare); bool Compare_ID(char* to_compare); bool Compare_Inventory(int to_compare); void Update(); void Alter_Title(char* new_name); void Print(); } 4)class Auction { private: list All_Objects; char* Title; public: Store(char* Title); ~Store(); //Functions that will be spawned off static void* Mod(void* Packed_Data); static void* Add(void* Packed_Data); static void* Del(void* Packed_Data); static void* Create(void* Packed_Data); static void* Printo(void* Packed_Data); static void* Printi(void* Packed_Data); static void* Load(void* Packed_Data); static void* Save(void* Packed_Data); } THESE ARE JUST HINTS :) DO NOT DUPLICATE !