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);
}
[email protected]:/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);
}
[email protected]:/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);
}
[email protected]:/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
那么就可以有下面这种结果
[email protected]:/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);
}
[email protected]:/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
那么就可以有下面这种结果
[email protected]:/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;
}
[email protected]:/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 结果可能就不一样,因为多线程读写操作。。。
[email protected]:/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
[email protected]:/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
[email protected]:/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);
}
[email protected]:/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
[email protected]:/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的结构,添加更多的细节