Monday, October 20, 2014

Unix Prog: Thread Creation

1. pthread_create

When program starts, it only has one thread. Additional thread can be created by system call: pthread_create.

Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Create a new thread, starting with execution of START-ROUTINE  
   getting passed ARG. Creation attributed come from ATTR. The new  
   handle is stored in *NEWTHREAD. */  
 extern int pthread_create (pthread_t *__restrict __newthread,  
               const pthread_attr_t *__restrict __attr,  
               void *(*__start_routine) (void *),  
               void *__restrict __arg) __THROWNL __nonnull ((1, 3));  
 ......  

1st argument is used to populate the newly created thread id
2nd argument is used to setup the thread attribute
3rd argument is used to setup the starting routine(function)
4th argument is used to setup the routine arguments. If there is more than one argument, need to provide the address of structure containing all arguments.

Note:
When a thread is created, there is no guarantee who runs firstly, calling thread or newly created thread.

The newly created thread will inherits the calling thread's floating-point environment and signal mask, but pending signals are cleared.

2. Example
thread.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<string.h>  
 #include<pthread.h>  
   
 pthread_t ntid;  
   
 void printids(const char *s)  
 {  
  pid_t pid;  
  pthread_t tid;  
   
  pid = getpid();  
  tid = pthread_self();  
  printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);  
 }  
   
 void* thr_fn(void *arg)  
 {  
  printids("new thread: ");  
  return((void *) 0);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int err;  
   
  // Create the new thread, populate the thread id on ntid,  
  // launch the function thr_fn as the starting routine  
  err = pthread_create(&ntid, NULL, thr_fn, NULL);  
  if(err != 0) {  
   printf("pthread_create error: %s!\n", strerror(err));  
   exit(1);  
  }  
   
  // Print information about main thread, but there is no guarantee  
  // that following output will appear firstly, maybe new thread is executed firstly  
  printids("main thread: ");  
   
  // Main thread sleep for one second to wait for new thread  
  // Otherwise if main thread is finished firstly, before the new thread  
  // is executed, the entire process is terminated.  
  sleep(1);  
  exit(0);  
 }  

shell:
1) We need to provide the pthread library, otherwise pthread_create will not be located.
2) main thread is executed firstly, and then new thread.
 ubuntu@ip-172-31-23-227:~$ gcc -g -pthread thread.c -o thread.out  
 ubuntu@ip-172-31-23-227:~$ ./thread.out  
 main thread: pid 29582 tid 2301646656 (0x89305740)  
 new thread: pid 29582 tid 2293282560 (0x88b0b700)  

Note: the new thread used pthread_self() to get its thread id, instead of referring to global "ntid". Because there is no guarantee main thread, new thread who will run firstly. It is possible that when new thread run, the ntid is still not populated.

In some systems, if pid is different, then that operating system use "clone" system call when calling the "pthread_create", and 2 processes are using some ways to share the execution context.

3. Unix Libraries
When using gcc, if the function or API declared in header files are already defined under gcc lib, then we need to do nothing. Otherwise, we need to specify our own library (path).

The upper part is GNU library, and the lower part is gcc lib.
We need to specify -pthread when using gcc to link, because pthread_create is defined inside libpthread.a which is part of gnu libs.
 ubuntu@ip-172-31-23-227:~$ sudo find /usr -name *.a  
 /usr/lib/libhgfs.a  
 /usr/lib/libguestlib.a  
 /usr/lib/x86_64-linux-gnu/librpcsvc.a  
 /usr/lib/x86_64-linux-gnu/libieee.a  
 /usr/lib/x86_64-linux-gnu/libBrokenLocale.a  
 /usr/lib/x86_64-linux-gnu/libanl.a  
 /usr/lib/x86_64-linux-gnu/libc_nonshared.a  
 /usr/lib/x86_64-linux-gnu/libmcheck.a  
 /usr/lib/x86_64-linux-gnu/libpthread.a  
 /usr/lib/x86_64-linux-gnu/libnsl.a  
 /usr/lib/x86_64-linux-gnu/libdl.a  
 /usr/lib/x86_64-linux-gnu/libresolv.a  
 /usr/lib/x86_64-linux-gnu/libg.a  
 /usr/lib/x86_64-linux-gnu/libpthread_nonshared.a  
 /usr/lib/x86_64-linux-gnu/libc.a  
 /usr/lib/x86_64-linux-gnu/libcrypt.a  
 /usr/lib/x86_64-linux-gnu/libutil.a  
 /usr/lib/x86_64-linux-gnu/librt.a  
 /usr/lib/x86_64-linux-gnu/libm.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libquadmath.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libssp_nonshared.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libitm.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_eh.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libasan.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libgomp.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libtsan.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libbacktrace.a  
 /usr/lib/gcc/x86_64-linux-gnu/4.8/libatomic.a  
 /usr/lib/libvmtools.a  

No comments:

Post a Comment