应用程序中有必要提供一种变量,使得多个函数多个线程都可以访问这个变量(如errno),但是线程对这个变量的访问都不会彼此产生影响。在使用私有数据之前,首先要创建一个私有数据相关的键,来获取对私有数据的访问权限 pthread_key_t .
int pthread_key_create (pthread_key_t *key, void (*destructor)(void *));
-创建的键放在key指向的单元,destructor是与键相关的析构函数。当线程调用pthread_exit或者return返回,析构函数就会被调用。函数只有一个参数,就是与key关联的那个数据的地址(私有数据),因此可以在析构函数中将这个数据销毁。
int pthread_key_delete (pthread_key_t key);
-销毁只会,与它关联的数据并没有被销毁
int pthread_setspecific (pthread_key_t key, const void *value);
-将私有数据和键关联起来。其中value就是不同的线程中,key值所关联的私有数据地址,这些地址可以用malloc来分配;
void *pthread_getspecific (pthread_key_t key);
-获取线程私有数据的地址,没有则返回NULL
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "limits.h"
pthread_key_t key;
void *thread_fun1(void *arg)
{
printf("thread 1 start\n");
int a=1;
pthread_setspecific(key,(void*)a);
sleep(2);
printf("thread 1 key->data is %d\n",pthread_getspecific(key));
}
void *thread_fun2(void *arg)
{
sleep(1);
printf("thread 2 start\n");
int a=2;
pthread_setspecific(key,(void*)a);
printf("thread 2 key->data is %d\n",pthread_getspecific(key));
}
int main()
{
pthread_t tid1,tid2;
pthread_key_create(&key,NULL);
int err;
err =pthread_create(&tid1,NULL,thread_fun1,NULL);
if(err!=0)
{
printf("create new thread failed\n");
return -1;
}
err =pthread_create(&tid2,NULL,thread_fun2,NULL);
if(err!=0)
{
printf("create new thread failed\n");
return -2;
}
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_key_delete(key);
return 0;
}
有关原理:
key原理详解
例子1:
当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量,读写锁,条件变量的状态继承过来。如果父进程中互斥量是锁着的,子进程的互斥量也是锁着的,这是非常不安全的,因为不是子进程自己锁住的,就无法解锁。
例子2:
子进程内部有一个线程,由父进程中调用fork函数的线程副本构成,如果调用fork的线程将互斥量锁住,那么子进程会拷贝一个pthread_mutex_lock副本,这样子进程就有机会去解锁了。
例子3:
多个prepare的执行顺序与注册顺序相反,而parent和child的执行顺序与注册顺序相同。
例子1:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "pthread.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_fun1(void *arg)
{
sleep(1);
pid_t pid;
pid = fork();
if(pid ==0)
{
pthread_mutex_lock(&mutex); //之前已经在main里锁住,这里会阻塞
printf("child\n");
pthread_mutex_unlock(&mutex);
}
if(pid >0)
{
pthread_mutex_lock(&mutex); //父进程可以锁,等待main中unlokc就能解锁
printf("parent\n");
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid;
if(pthread_create(&tid,NULL,thread_fun1,NULL))
{
printf("create thread failed");
}
pthread_mutex_lock(&mutex);
sleep(2);
pthread_mutex_unlock(&mutex);
printf("main\n");
pthread_join(tid,NULL);
return;
}
例子2:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "pthread.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_fun1(void *arg)
{
sleep(1);
pid_t pid;
pthread_mutex_lock(&mutex);
pid = fork();
if(pid ==0)
{
pthread_mutex_unlock(&mutex);// 拷贝了一个解锁副本,可以解锁
printf("child\n");
}
if(pid >0)
{
pthread_mutex_unlock(&mutex);
printf("parent\n");
}
}
int main()
{
pthread_t tid;
if(pthread_create(&tid,NULL,thread_fun1,NULL))
{
printf("create thread failed");
}
printf("main\n");
pthread_join(tid,NULL);
return;
}
例子3:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "pthread.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态
void prepare()
{
pthread_mutex_lock(&mutex);
printf("i am prepare\n");
}
void parent()
{
pthread_mutex_unlock(&mutex);
printf("i am parent\n");
}
void child()
{
pthread_mutex_unlock(&mutex);
printf("i am child\n");
}
void *thread_fun1(void *arg)
{
sleep(1);
pid_t pid;
pthread_atfork(prepare,parent,child);//先调用prepare上锁,此时两个锁。后解锁两次
pid = fork();
if(pid ==0)
{
pthread_mutex_lock(&mutex);
printf("child process\n");
pthread_mutex_unlock(&mutex);
}
if(pid >0)
{
pthread_mutex_lock(&mutex); //父进程可以锁,等待main中unlokc就能解锁
printf("parent process\n");
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid;
if(pthread_create(&tid,NULL,thread_fun1,NULL))
{
printf("create thread failed");
}
pthread_mutex_lock(&mutex);
sleep(2);
pthread_mutex_unlock(&mutex);
printf("main\n");
pthread_join(tid,NULL);
return;
}