After the threads have done enough operations, you should expect your shared data to become corrupted. Design your threads to detect the corruption, report it and stop. Only report a situation where the data has become inconsistent because the update was not done in a critical section.
You will want each thread to tell the other thread that an error in the data has been observed, by storing a value in a shared variable. That way, the other thread can stop when the error has been detected.
Run your program. Time it to see how long it takes before the data becomes corrupted. Add a comment to the top of the program text indicating about how long it took to detect corrupted data.
To create threads, you start by creating a structure that describes desired thread attributes. You can then use that structure to create many threads with those attributes. Create a variable attr of type pthread_attr_t, and initialize it as follows.
pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);The first line installs the default attributes. The second line indicates that the thread manager should switch between threads in a way similar to the way the system's process manager switches between processes. That is, preemptive scheduling of the threads is used. (The default is to use cooperative multiprogramming among the threads.)
Then create the thread as follows.
status = pthread_create(&tid, &attr, func, NULL);where
tid is a variable of type pthread_t (typically another name for unsigned int). It will be set to the thread id, an integer.
func is a function that the thread will run. The prototype for func should be
void* func(void*);(You don't have to call the function func. You can call it any name that you like. But it must take a parameter of type void*, and produce a result of type void*.) Make func return NULL.
status is a variable of type int. Function pthread_create returns 0 if the thread was created, and a nonzero value if there was an error that prevented creation of the thread.
The last parameter of pthread_create is the parameter that is passed to func when the thread starts. It has type void*. So, when pthread_create(tid,func,a,p) starts, it runs f(p). The line above shows this parameter set to NULL. If you like, you can set it to an integer k, as in
status = pthread_create(&tid, &attr, func, (void*) k);That allows you to used the same function func with two different parameters, so that the threads can tell which is which.
When the thread is created it starts running immediately.
You will need to create two threads, and then wait for the threads to terminate. (If you don't wait, and you let the main program terminate, the threads that it created will be destroyed prematurely.) Function pthread_join allows one thread to wait for another one. Use
pthread_join(tid,NULL);to wait for thread number tid to terminate before continuing. Since you will have created two threads, you will have to wait for both of them. You will have to wait for them in a specific order. It does not matter which one finishes first. A terminated thread waits until another thread joins with it before it disappears. (It becomes a zombie thread.)
gcc myprog.c -lpthread
When using threads, it is a good idea to include directive
#define _REENTRANTto force the compiler to generate reentrant code. (Most compilers do this anyway.) Reentrant code has a read-only TEXT segment (where the program is stored) so that it can be run simultaneously by more than one thread.
time_t tloc; char buff[50]; time(&tloc); printf("%s", ctime_r(&tloc, buff, 50));Include header file time.h to use these. The POSIX function ctime_r is a little different. It takes only the first two parameters; drop the 50 for it.
sema_t sp; sema_init(&sp, 1, USYNC_THREAD, NULL);Now use
sema_wait(&sp);to do a wait on semaphore sp, and
sema_post(&sp);to do a signal on sp. When you are finished with the semaphore, destroy it using
sema_destroy(&sp);
alias handin "/export/stu/classes/csci4630/bin/handin csci4630" handin 2 thread1.c thread2.c