《APUE》chapter 11 Thread 学习笔记(加上自己的代码)

Thread

                All threads  within  a  single  process  have  access  to  the  same  process components, such as file descriptors and memory







Thread Concepts

                A typical  UNIX  process  can  be  thought  of  as  having  a  single  thread  of  control:  each process  is  doing  only one  thing  at  a  time. With  multiple  threads  of  control,  we  can design our programs to do more than one thing at a time within a single process, with each thread handling a separate task. 

             

               Two tasks  can  be  interleaved  only  if  they don’t depend on the processing performed by each other.

             

               Furthermore,  as  long  as  your  program  has  to block  when  serializing  tasks,  you  can  still  see  improvements  in  response  time  and throughput when running on a uniprocessor ,because some threads might be able to run while others are blocked.

  

          Everything within a process is sharable among the threads in a process, including the text of the executable
program, the program’s global and heap memory ,the stacks, and the file descriptors.


Thread Identification


             Just as every process has a process ID, every thread has a thread ID. Unlike the process ID, which is unique in the system, the thread ID has significance only within the context of the process to which it belongs


             A thread ID is represented by the pthread_t data type. 

typedef unsigned long int pthread_t;

值得一提的是linux的pthread_t 并不是一个结构体,而是unsigned long int


#include <pthread.h>
int pthread_equal(pthread_t tid1 ,pthread_t tid2 );
Returns: nonzero if equal, 0 otherwise



A thread can obtain its own thread ID by calling the pthread_selffunction

#include <pthread.h>
pthread_t pthread_self(void);
Returns: the thread ID of the calling thread





Thread Creation



#include <pthread.h>
int pthread_create(pthread_t *restrict  tidp ,const pthread_attr_t *restrictattr , void *(* start_rtn )(void *), void *restrictarg);
Returns: 0 if OK, error number on failure



             The  memory  location  pointed  to  by tidp is  set  to  the  thread  ID  of  the  newly  created thread  when pthread_create re turns  successfully. The attr argument  is  used to customize  various  thread  attributes.we’ll set this to NULL to create a thread with the default attributes


         The  newly  created  thread  starts  running  at  the  address  of  the start_rtn function.This  function  takes  a  single  argument, arg,which  is  a  typeless  pointer.


          When  a  thread  is  created,  there is no guarantee  which  will  run  first.  however,t he set of pending signals for the thread is cleared.



#include"apue.h"
#include<pthread.h>
#include<myerr.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)pid);
}


void* thr_fn(void*arg)
{
        printids("new thread:");
        return ((void*)0);
}


int main()
{
        int err;


        err = pthread_create(&ntid,NULL,thr_fn,NULL);
        if(err != 0)
        {
                err_quit("can't creat thread: %s\n",strerror(err));
        }
        printids("main thread:");
        sleep(1);
        exit(0);
}

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
main thread: pid 7496 tid 3495302976 (0x1d48) 
new thread: pid 7496 tid 3486983936 (0x1d48)


          The first is the need to sleep in the main thread.  If it doesn’t sleep, the main  thread  might  exit,  thereby  terminating  the  entire process  before the  new  thread gets  a  chance  to  run.





Thread Termination


         A single thread can exit in three ways, thereby stopping its flow of control, without terminating the entire process.

1.  The thread  can  simply  return  from  the  start  routine.  The re turn  value  is  the thread’s exit code.

2.  The thread can be canceled by another thread in the same process.

3.  The thread can call pthread_exit



#include <pthread.h>
void pthread_exit(void *rval_ptr);

#include <pthread.h>
int pthread_join(pthread_t thread ,void **rval_ptr);
Returns: 0 if OK, error number on failure



           The  calling  thread  will  block  until  the  specified  thread  calls pthread_exit,returns from its start routine, or is canceled. If we’re not interested in a thread’s return value, we can set rval_ptr to NULL.

demo:

#include"apue.h"
#include<pthread.h>
#include"myerr.h"


void* thr_fn1(void* arg)
{
        printf("thread 1 returning\n");
        return ((void*)1);
}


void * thr_fn2(void * arg)
{
        printf("thread 2 exiting\n");
        return ((void*)2);
}


int main()
{
        int err;
        pthread_t tid1,tid2;
        void    *tret;


        err = pthread_create (&tid1,NULL,thr_fn1,NULL);
        if(err != 0)
        {
                err_quit("can't create thread 1:%s\n",strerror(err));
        }


        err = pthread_create(&tid2,NULL,thr_fn2,NULL);
        if(err != 0)
        {
                err_quit("can't create thread 2:%s\n",strerror(err));
        }


        err = pthread_join(tid1,&tret);
        if(err != 0)
        {
                err_quit("can't join with thread 1:%s\n",strerror(err));
        }

        printf("thread 1 exit code %d\n",(int)tret);
        err = pthread_join(tid2,&tret);
        if(err != 0)
        {
                err_quit("can't join with thread 2:%s\n",strerror(err));
        }


        printf("thread 2 exit code %d\n",(int)tret);
        exit(0);
}


jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 1 returning
thread 1 exit code 1
thread 2 exiting
thread 2 exit code 2


when  a  thread  exits  by  calling pthread_exitor  by  simply  returning from  the  start  routine,  the  exit  status  can be  obtained  by  another  thread  by  calling pthread_join.






#include"apue.h"
#include"myerr.h"
#include<pthread.h>


struct foo
{
         int a,b,c,d;
};


//struct foo foo ={1,2,3,4};


void printfoo(const char*s,const struct foo* fp)
{
        printf(s);
        printf("structure at 0x%x\n",(unsigned)fp);
        printf(" foo.a = %d\n",fp->a);
        printf(" foo.b = %d\n",fp->b);
        printf(" foo.c = %d\n",fp->c);
        printf(" foo.d = %d\n",fp->d);
}


void* thr_fn1(void* arg)
{
        struct foo foo ={1,2,3,4};
        printfoo("thread 1:\n",&foo);
        pthread_exit((void*)&foo);
}


void* thr_fn2(void* arg)
{
        printf("thread 2: ID is %d\n",pthread_self());
        pthread_exit((void*) 0);
}
int main()
{
        int err;
        pthread_t tid1,tid2;
        struct foo *fp;


        err = pthread_create(&tid1,NULL,thr_fn1,NULL);
        if(err != 0)
        {
                err_quit("can't creat thread 1:%s\n",strerror(err));
        }


        err = pthread_join(tid1,(void*) &fp);
        if(err != 0)
        {
                err_quit("can't join with thread 1:%s\n",strerror(err));
        }


        sleep(1);
        printf("parent starting second thread \n");
        err = pthread_create(&tid2,NULL,thr_fn2,NULL);
        if(err != 0)
        {
                err_quit("can't creat thread 2:%s\n",strerror(err));
        }


        sleep(1);
        printfoo("parent:\n",fp);
        exit(0);
}


jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 1:
structure at 0x88082e90
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4
parent starting second thread 
thread 2: ID is -2012727552
parent:
structure at 0x88082e90
 foo.a = 0
 foo.b = 0
 foo.c = 1
 foo.d = 0


这个demo在我看来。。。除了说明一下thread之外无非就是说了一个局部自动变量的作用范围问题。。。


只要把上面我注释掉的部分,用起来(就是把注释符号去掉)。并且注释掉局部的foo

那么就可以有下面这种结果

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 1:
structure at 0x6020c0
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4
parent starting second thread 
thread 2: ID is -430766336
parent:
structure at 0x6020c0
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4



#include <pthread.h>
void pthread_cleanup_push(void (* rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute );































#include"apue.h"
#include"myerr.h"
#include<pthread.h>


struct foo
{
         int a,b,c,d;
};


//struct foo foo ={1,2,3,4};


void printfoo(const char*s,const struct foo* fp)
{
        printf(s);
        printf("structure at 0x%x\n",(unsigned)fp);
        printf(" foo.a = %d\n",fp->a);
        printf(" foo.b = %d\n",fp->b);
        printf(" foo.c = %d\n",fp->c);
        printf(" foo.d = %d\n",fp->d);
}


void* thr_fn1(void* arg)
{
        struct foo foo ={1,2,3,4};
        printfoo("thread 1:\n",&foo);
        pthread_exit((void*)&foo);
}


void* thr_fn2(void* arg)
{
        printf("thread 2: ID is %d\n",pthread_self());
        pthread_exit((void*) 0);
}
int main()
{
        int err;
        pthread_t tid1,tid2;
        struct foo *fp;


        err = pthread_create(&tid1,NULL,thr_fn1,NULL);
        if(err != 0)
        {
                err_quit("can't creat thread 1:%s\n",strerror(err));
        }


        err = pthread_join(tid1,(void*) &fp);
        if(err != 0)
        {
                err_quit("can't join with thread 1:%s\n",strerror(err));
        }


        sleep(1);
        printf("parent starting second thread \n");
        err = pthread_create(&tid2,NULL,thr_fn2,NULL);
        if(err != 0)
        {
                err_quit("can't creat thread 2:%s\n",strerror(err));
        }


        sleep(1);
        printfoo("parent:\n",fp);
        exit(0);
}


jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 1:
structure at 0x88082e90
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4
parent starting second thread 
thread 2: ID is -2012727552
parent:
structure at 0x88082e90
 foo.a = 0
 foo.b = 0
 foo.c = 1
 foo.d = 0


这个demo在我看来。。。除了说明一下thread之外无非就是说了一个局部自动变量的作用范围问题。。。


只要把上面我注释掉的部分,用起来(就是把注释符号去掉)。并且注释掉局部的foo

那么就可以有下面这种结果

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 1:
structure at 0x6020c0
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4
parent starting second thread 
thread 2: ID is -430766336
parent:
structure at 0x6020c0
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4




#include <pthread.h>
int pthread_cancel(pthread_t tid);
Returns: 0 if OK, error number on failure

#include <pthread.h>
void pthread_cleanup_push(void (* rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute );



demo:

#include "apue.h"
#include "myerr.h"
#include "pthread.h"


void cleanup(void *arg)
{
        printf("clearn up :%s\n",(char*)arg);
}


void *thr_fn1(void *arg)
{
        printf("thread 1 start\n");
        pthread_cleanup_push(cleanup,"thread 1 first handler\n");
        pthread_cleanup_push(cleanup,"thread 1 second hanler\n");
        printf("thread 1 push complete\n");


        if(arg)
        {
                return((void*) 1);
        }
        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
        return ((void*) 1);
}


void *thr_fn2(void *arg)
{
        printf("thread 2 start\n");
        pthread_cleanup_push(cleanup,"thread 2 first handler");
        pthread_cleanup_push(cleanup,"thread 2 second handler");
        printf("thread 2 push complete\n");


        if(arg)
        {
                pthread_exit((void*) 2);
        }


        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
        pthread_exit((void*) 2);
int main()
{
        int err;
        pthread_t tid1,tid2;
        void* tret;


        err = pthread_create(&tid1,NULL,thr_fn1,(void*) 1);
        if(err != 0)
        {
                err_quit("can't create thread 1 :%s\n",strerror(err));
        }


        err = pthread_create(&tid2,NULL,thr_fn2,(void*) 2);
        if(err != 0)
        {
                err_quit("can't create thread 2 :%s\n",strerror(err));
        }


        err = pthread_join(tid1,&tret);
        if(err != 0)
        {
                err_quit("can't join with thread 1:%s\n",strerror(err));
        }


        printf("thread 1 exit code %d\n",(int)tret);
        err = pthread_join(tid2,&tret);
        if(err != 0)
        {
                err_quit("can't join with thread 2:%s\n",strerror(err));
        }


        printf("thread 2 exit code %d\n",(int)tret);


        return 0;
}

liuzjian@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
thread 2 start
thread 2 push complete
thread 1 start
thread 1 push complete
clearn up :thread 2 second handler
clearn up :thread 2 first handler
thread 1 exit code 1
thread 2 exit code 2


        if the thread terminates by returning from its start routine, its cleanup handlers are not called, although this behavior varies among  implementations. Also  note  that  the  cleanup  handlers  are called  in  the  reverse order from which they were installed.


        By  default,  a  thread’s  termination  status  is  retained  until  we  call pthread_join for  that  thread.



        After a thread is detached, we can’t use the pthread_join function  to  wait  for  its  termination  status,  because calling pthread_join for  a  detached  thread  results  in  undefined  behavior.

进程线程相关函数对比:




Thread Synchronization

       

        When  one  thread  modifies  a  variable,  other  threads  can  potentially  see inconsistencies  when  reading  the  value  of  that  variable.


         If  two  threads try  to  increment  the  same  variable  at  almost  the  same  time  without synchronizing with each other ,the results can be inconsistent. 


        Figure11.7  shows  a  hypothetical  example  of  two  threads  reading  and  writing  the same variable. In this example, thread A reads the variable and then writes a new value to  it,  but  the  write  operation  takes  two memory cycles. If  thread  B  reads  the  same variable between the two write cycles, it will see an inconsistent value.






        To  solve this problem, the threads have to use a lock that will allow only one thread to  access  the  variable  at  a  time.


Mutexes

         We  can  protect  our  data  and  ensure access  by  only  one  thread  at  a  time  by  using  the pthreads  mutual-exclusion  interfaces.  A mutex is  basically  a  lock  that  we  set  (lock) before accessing  a  shared  resource  and release  (unlock)  when  we’re done.  While it  is set,  any  other  thread  that  tries  to  set  it  will  block  until  we release  it.


In this way ,only one thread will proceed at a time.



#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrictattr );
int pthread_mutex_destroy(pthread_mutex_t * mutex);
Both return: 0 if OK, error number on failure

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t * mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
All return: 0 if OK, error number on failure

To  initialize  a  mutex  with  the  default  attributes,  we  set attr to NULL


          If  a  thread  can’t  afford to block,  it  can  use pthread_mutex_trylock to  lock  the mutex  conditionally. If the  mutex  is  unlocked  at  the  time pthread_mutex_trylock is  called,  then pthread_mutex_trylock will  lock  the  mutex  without  blocking  and return  0. Otherwise, pthread_mutex_trylock will  fail,  returning EBUSY without locking the mutex.


测试pthread_mutexes_trylock 和pthread_mutexes_lock貌似我还没找出区别。。。测试结果差不多

最重要的还是demo:........


#include"stdio.h"
#include"stdlib.h"
#include<pthread.h>
#include"string.h"


void *myfunc1(void* ptr);
void *myfunc2(void* ptr);


pthread_mutex_t lock;
int a[100];


int main()
{
        pthread_t thrd1,thrd2;
        int thret1,thret2;
        char* msg1 = "First thread";
        char* msg2 = "Second thread";


        memset(a,0,sizeof(a));


        thret1 = pthread_create(&thrd1,NULL,myfunc1,(void *)msg1);
        thret2 = pthread_create(&thrd2,NULL,myfunc2,(void *)msg2);


        pthread_join(thrd1,NULL);
        pthread_join(thrd2,NULL);


        printf("thret1 = %d\n",thret1);
        printf("thret2 = %d\n",thret2);


        return 0;
}

void* myfunc1(void* ptr)
{
        int i;
        char* msg = (char*) ptr;
        printf("msg: %s\n",msg);


        pthread_mutex_lock(&lock);
        for(i = 0;i < 100;i++)
        {
                printf("X");
                a[i] = i;
        }
        printf("\n");
        pthread_mutex_unlock(&lock);
}


void* myfunc2(void* ptr)
{
        int i;
        char* msg =(char*)ptr;
        printf("msg: %s\n",msg);


        pthread_mutex_lock(&lock);
        for(i = 0;i< 100;i++)
        {
                printf("%d, ",a[i]);
        }
        printf("\n");
        pthread_mutex_unlock(&lock);
}


多运行几次a.out 结果可能就不一样,因为多线程读写操作。。。

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
msg: Second thread
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
msg: First thread
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
thret1 = 0
thret2 = 0
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
msg: Second thread
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, msg: First thread


XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
thret1 = 0
thret2 = 0
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
msg: First thread
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
msg: Second thread
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 
thret1 = 0
thret2 = 0


上面这个代码为了快速理解mutexes写的,很多细节都不是很好,可以看下面的demo,更好的规范使用mutexes

看APUE的那个demo不止看了三次。。。还是没看明白。。。今天才明白。。。

writer没给main 函数测试难过。。。But now I give it.

和上面的demo 不同的是,APUE给出的demo要规范的多,让我打心底里深深的佩服啊

作者很细致的把lock封装在结构体里面。


#include "apue.h"
#include <pthread.h>
#include "myerr.h"


struct foo
{
        int f_count;
        pthread_mutex_t f_lock;
};


struct foo* foo_alloc(void);


void foo_hold(struct foo*fp);


void foo_rele(struct foo*fp);


void *myfunc1(void* ptr);
void *myfunc2(void* ptr);




int a[100];


int main()
{
        int err = 0;


        int thret1,thret2;
        pthread_t thrd1,thrd2;
        struct foo* fp = NULL;


        memset(a,0,sizeof(a));


        fp = foo_alloc();


        thret1 = pthread_create(&thrd1,NULL,myfunc1,(void *)fp);
        thret2 = pthread_create(&thrd2,NULL,myfunc2,(void *)fp);



        if((err = pthread_join(thrd1,NULL)) != 0)
        {
                printf("join error %s\n",strerror(err));
        }


        if((err = pthread_join(thrd2,NULL)) != 0)
        {
                printf("join error %s\n",strerror(err));
        }


        printf("thret1 = %d\n",thret1);
        printf("thret2 = %d\n",thret2);
        return 0;
}


struct foo* foo_alloc(void)
{
        struct foo* fp;


        if((fp = malloc(sizeof(struct foo))) != NULL)
        {
                fp->f_count = 1;
                if(pthread_mutex_init(&fp->f_lock,NULL) != 0)
                {
                        free(fp);
                        return NULL;
                }


                /*continue initialization*/
        }
        return (fp);
}


void foo_hold(struct foo*fp)
{
        pthread_mutex_lock(&fp->f_lock);
        fp->f_count++;
//      pthread_mutex_unlock(&fp->f_lock);
}

void foo_rele(struct foo*fp)
{
//      pthread_mutex_lock(&fp->f_lock);
        if(--fp->f_count == 0)
        {
                pthread_mutex_unlock(&fp->f_lock);
                pthread_mutex_destroy(&fp->f_lock);
                free(fp);
        }
        else
        {
                pthread_mutex_unlock(&fp->f_lock);
        }
}


void* myfunc1(void* ptr)
{
        int i;
        struct foo* fp  = (struct foo*) ptr;


        foo_hold(fp);


        printf("msg: thread 1\n");


        for(i = 0;i < 100;i++)
        {
                printf("X");
                a[i] = i;
        }
        printf("\n");
        foo_rele(fp);
}

void* myfunc2(void* ptr)
{
        int i;
        struct foo* fp  = (struct foo*) ptr;


        foo_hold(fp);


        printf("msg: thread2\n");


        for(i = 0;i< 100;i++)
        {
                printf("%d, ",a[i]);
        }
        printf("\n");
        foo_rele(fp);
}

jasonleaser@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
msg: thread2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 
msg: thread 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
thret1 = 0
thret2 = 0
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_11$ ./a.out
msg: thread 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
msg: thread2
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74
, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 
thret1 = 0
thret2 = 0


值得注意的是代码里面和APUE给的有点不同,我特意注释掉了两行代码。如果不注释掉那部分我实在解释不通。。。程序也有问题。

上面这个demo很好的采用了结构体来作为lock单元,而不是一个单独的pthread_mutexes_t类型变量。并且可以细心的发现,我测试的时候是把foo_alloc 放在线程之外的进程之中。所并“不属于”任意线程,他创建在进程之中,让各个线程使用它,这样,一个锁,多个线程用,就可以避免接下来要讨论的死锁的问题。如果我们不把foo_alloc放在进程中,而是放在myfunc*之中,为每个线程分别创建一个锁,那么就极有可能出现死锁!


Deadlock Avoidance

A thread  will  deadlock  itself  if  it  tries  to  lock  the  same  mutex  twice。


For example, when we use more than one  mutex  in  our  programs,  a  deadlock  can  occur  if  we  allow  one thread  to  hold  a mutex  and  block  while  trying  to  lock  a  second  mutex  at  the  same  time  that  another
thread  holding  the  second  mutex  tries  to  lock  the  first  mutex.



作者给的示意性代码真心有问题。

http://blog.csdn.net/cinmyheart/article/details/22863095

以后我自己写个demo补上来。。。吧。。。

It's a pity。。。






Deadlock Avoidance

A thread  will  deadlock  itself  if  it  tries  to  lock  the  same  mutex  twice。


For example, when we use more than one  mutex  in  our  programs,  a  deadlock  can  occur  if  we  allow  one thread  to  hold  a mutex  and  block  while  trying  to  lock  a  second  mutex  at  the  same  time  that  another
thread  holding  the  second  mutex  tries  to  lock  the  first  mutex.




作者给的示意性代码真心有问题。

http://blog.csdn.net/cinmyheart/article/details/22863095

以后我自己写个demo不上来。。。吧。。。



Reader–writer locks


           Reader–writer locks are similar to mutexes, except that they allow for higher degrees of parallelism.  With  a  mutex, the  state  is  either  locked  or  unlocked,  and  only  one  thread can lock it at a time. Three states are possible with a reader–writer lock: locked in read mode,  locked  in  write  mode,  and  unlocked. Only  one  thread  at  a  time  can  hold  a reader–writer lock in write mode, but multiple threads can hold a reader–writer lock in read mode at the same time.


#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrictrwlock ,
const pthread_rwlockattr_t *restrict attr );
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock );
Both return: 0 if OK, error number on failure

#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock );
All return: 0 if OK, error number on failure

#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock );
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock );
Both return: 0 if OK, error number on failure


API和mutexes的差不多。最终看看demo就行了


未完待续。。。有部分demo没有给出,近日将给出demo。并更改blog的结构,添加更多的细节







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值