Sunday, October 26, 2014

Unix Prog: Thread Attributes

1. Some Thread limitations
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/local_lim.h  
 ......  
 /* The number of data keys per process. */  
 #define _POSIX_THREAD_KEYS_MAX 128  
 /* This is the value this implementation supports. */  
 #define PTHREAD_KEYS_MAX    1024  
 ......  
 /* Controlling the iterations of destructors for thread-specific data. */  
 #define _POSIX_THREAD_DESTRUCTOR_ITERATIONS   4  
 /* Number of iterations this implementation does. */  
 #define PTHREAD_DESTRUCTOR_ITERATIONS  _POSIX_THREAD_DESTRUCTOR_ITERATIONS  
 ......  
 /* The number of threads per process. */  
 #define _POSIX_THREAD_THREADS_MAX    64  
 /* We have no predefined limit on the number of threads. */  
 #undef PTHREAD_THREADS_MAX  
 ......  
 /* Minimum size for a thread. We are free to choose a reasonable value. */  
 #define PTHREAD_STACK_MIN    16384  
 ......  

2. Thread Attributes

System Definitions:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Initialize thread attribute *ATTR with default attributes  
   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,  
   no user-provided stack). */  
 extern int pthread_attr_init (pthread_attr_t *__attr) __THROW __nonnull ((1));  
   
 /* Destroy thread attribute *ATTR. */  
 extern int pthread_attr_destroy (pthread_attr_t *__attr)  
    __THROW __nonnull ((1));  
 ......  
We can use the pthread_attr_t structure to modify the default attributes, and associate these attributes with threads that we create.

We use the pthread_attr_init function to initialize pthread_attr_t data structure.

pthread_attr_t structure is supposed to be opaque to applications. Application should use API to query and set the attribute. This helps improve the portability.

3. Attribute -- Detachable State

System Definitions:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Get detach state attribute. */  
 extern int pthread_attr_getdetachstate (const pthread_attr_t *__attr,  
                     int *__detachstate)  
    __THROW __nonnull ((1, 2));  
   
 /* Set detach state attribute. */  
 extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,  
                     int __detachstate)  
    __THROW __nonnull ((1));  
 ......  
/* Detach state.  */
enum
{
  PTHREAD_CREATE_JOINABLE,
#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE
  PTHREAD_CREATE_DETACHED
#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED
};
......

Thread with detachable state: allow the operating system to recliam the thread's resources when thread exits.

The second parameter in above functions can be either PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

Example:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<pthread.h>  
   
 void* thd_fn(void *vd)  
 {  
  // sleep for 1 second to let main thread run pthread_attr_destroy firstly  
  sleep(1);  
  printf("Hello world!\n");  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int err;  
  pthread_t tid;  
  pthread_attr_t attr;  
   
  // Initialize attributes  
  err = pthread_attr_init(&attr);  
  if(err != 0) {  
   printf("pthread_attr_init error!\n");  
   exit(err);  
  }  
   
  err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  
   
  // Create and launch the thread  
  if(err == 0)  
   err = pthread_create(&tid, &attr, thd_fn, NULL);  
  pthread_attr_destroy(&attr);  
   
  // Sleep for 2 seconds to let thread finish  
  sleep(2);  
  return err;  
 }  

shell:
The program launched the thread firstly, the thread wait for 1 second, during this period, main thread finish calling pthread_attr_destroy and start waiting for 2 seconds. During this period, the thread finish and return.
This indicates that, pthread_attr_destroy is called before thread finish is ok.
 ubuntu@ip-172-31-23-227:~$ ./thread.out  
 Hello world!  

4. Other Attributes API:
The usage is same as above example for detachable state.

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Return the previously set address for the stack. */  
 extern int pthread_attr_getstackaddr (const pthread_attr_t *__restrict  
                    __attr, void **__restrict __stackaddr)  
    __THROW __nonnull ((1, 2)) __attribute_deprecated__;  
   
 /* Set the starting address of the stack of the thread to be created.  
   Depending on whether the stack grows up or down the value must either  
   be higher or lower than all the address in the memory block. The  
   minimal size of the block must be PTHREAD_STACK_MIN. */  
 extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,  
                    void *__stackaddr)  
    __THROW __nonnull ((1)) __attribute_deprecated__;  
   
 /* Return the currently used minimal stack size. */  
 extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict  
                    __attr, size_t *__restrict __stacksize)  
    __THROW __nonnull ((1, 2));  
   
 /* Add information about the minimum stack size needed for the thread  
   to be started. This size must never be less than PTHREAD_STACK_MIN  
   and must also not exceed the system limits. */  
 extern int pthread_attr_setstacksize (pthread_attr_t *__attr,  
                    size_t __stacksize)  
    __THROW __nonnull ((1));  
   
 #ifdef __USE_XOPEN2K  
 /* Return the previously set address for the stack. */  
 extern int pthread_attr_getstack (const pthread_attr_t *__restrict __attr,  
                  void **__restrict __stackaddr,  
                  size_t *__restrict __stacksize)  
    __THROW __nonnull ((1, 2, 3));  
   
 /* The following two interfaces are intended to replace the last two. They  
   require setting the address as well as the size since only setting the  
   address will make the implementation on some architectures impossible. */  
 extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,  
                  size_t __stacksize) __THROW __nonnull ((1));  
 ......  

Within the process, the virtual address space is shared by all threads.
If you run out of virtual address space for thread stacks, you can use malloc or mmap to allocate space for an alternate stack and use pthread_attr_setstack to change the stack location of threads you create.

The guardsize thread attribute controls the size of the memory extent after the end of the thread's stack to protect against stack overflow. If we change the stackaddr thread attribute, the system assumes that we will be managing our stacks and disables stack guard buffers, just as if we had set the guardsize thread attribute to 0.

If the thread's stack pointer overflow into the guard area, the application will receive an error, possibly with a signal.

Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Get the size of the guard area created for stack overflow protection. */  
 extern int pthread_attr_getguardsize (const pthread_attr_t *__attr,  
                    size_t *__guardsize)  
    __THROW __nonnull ((1, 2));  
   
 /* Set the size of the guard area created for stack overflow protection. */  
 extern int pthread_attr_setguardsize (pthread_attr_t *__attr,  
                    size_t __guardsize)  
    __THROW __nonnull ((1));  
 ......  

Concurrency level:
Concurrency level indicates how many user threads can be mapped to several kernel facilities simultaneously. Unix allows user to get and set the concurrency level to adjust the process performance, but different implementations varies. OS has to right to ignore user's request. If return value or setup value is 0, then thread's concurrency level is controlled completely by OS.

Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Determine level of concurrency. */  
 extern int pthread_getconcurrency (void) __THROW;  
   
 /* Set new concurrency level to LEVEL. */  
 extern int pthread_setconcurrency (int __level) __THROW;  
 ......  

No comments:

Post a Comment