lesson5 线程的高级属性

来源:互联网 发布:淘宝卖家怎么设置限购 编辑:程序博客网 时间:2024/04/29 23:06

1. 一次性初始化:

互斥量智能初始化一次,再次初始化会出现错误。比如自己写库函数时将互斥量封装进去,这时一次性初始化就用上场了。

定义变量pthread_once_t once_control = PTHREAD_ONCE_INIT;

void init_routine(){

//初始化互斥量

//初始化读写锁

}

接下来在函数pthread_once引用上述变量和函数,多线程只会执行函数指针一次。 

2. 线程属性

创建线程时可以使用pthread_attr_t类型参数变更属性。

如:

a. detachstate线程的分离状态

b. guardsize线程栈末尾的警戒区域大小//预防栈溢出

c. stackaddr线程栈的最低地址

d. stacksize线程栈的大小//不能小于最小值

并不是全部线程都支持这些熟悉,修改前需要先检查。


pthread_attr_setstack //修改栈地址、大小

pthread_attr_getstack //获取栈属性


pthread_attr_setstacksize //设置大小,不能设地址

pthread_attr_sgetstacksize


3. 线程的同步属性

1). 互斥量的属性:

a.进程共享属性:PTHREAD_PROCESS_PRIVATE,同一进程的多个线程访问权限;PTHREAD_PROCESS_SHARED:多个进程访问权限。

如果互斥量在多进程的共享内存区域,那么具有这个属性的互斥量可以同步多进程。

pthread_mutexattr_getpshared/pthread_mutexattr_setshared设置、获取互斥量进程共享属性。

b.类型属性:设置互斥量的类型属性,PTHREAD_MUTEX_NORMAL等;

pthread_mutexattr_settype/pthread_mutexattr_gettype设置、查看出现

2).读写锁属性

3)条件变量属性

4. 示例,互斥量属性操作

#include "apue.h"int main(){char *shm = "myshm";char *shm1 = "myshm1";int shm_id, shm_id1;char *buf;pid_t pid;pthread_mutex_t *mutex;pthread_mutexattr_t mutexattr;//打开共享内存shm_id1 = shm_open(shm1, O_RDWR|O_CREAT, 0644);//调整共享内存大小ftruncate(shm_id1, 100);//映射共享内存,MAP_SHARED属性表明,对共享内存的任何修改都会影响其他进程mutex =(pthread_mutex_t *)mmap(NULL, 100, PROT_READ|PROT_WRITE, MAP_SHARED, shm_id1, 0);pthread_mutexattr_init(&mutexattr);#ifdef _POSIX_THREAD_PROCESS_SHAREDpthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);#endifpthread_mutex_init(mutex, &mutexattr);//打开共享内存shm_id = shm_open(shm, O_RDWR|O_CREAT, 0644);//调整共享内存大小ftruncate(shm_id, 100);//映射共享内存,MAP_SHARED属性表明,对共享内存的任何修改都会影响其他进程buf =(char *)mmap(NULL, 100, PROT_READ|PROT_WRITE, MAP_SHARED, shm_id, 0);pid = fork();if(pid==0){//休眠1s,让父进程先运行sleep(1);printf("I'm child proccess\n");pthread_mutex_lock(mutex);//将共享内存内存修改为hellomemcpy(buf, "hello", 6);printf("child buf is : %s\n", buf);pthread_mutex_unlock(mutex);}else if(pid>0){printf("I'm parent proccess\n");pthread_mutex_lock(mutex);//修改共享内存到内容,改为worldmemcpy(buf, "world", 6);sleep(3);printf("parent buf is : %s\n", buf);pthread_mutex_unlock(mutex);}pthread_mutexattr_destroy(&mutexattr);pthread_mutex_destroy(mutex);//解除映射munmap(buf, 100);//消除共享内存shm_unlink(shm);//解除映射munmap(mutex, 100);//消除共享内存shm_unlink(shm1);}


5. 线程私有数据

多个函数多个进程可以访问这个变量,看起来像全局变量;但是它又不是全局变量,线程对这个变量的访问不会彼此产生影响。比如参数errno。

使用私有数据前,要先创建一个与私有数据相关的key,类型pthread_key_t.

使用函数pthread_key_create创建键,创建的键放在参数key指向的内存单元,另一个参数destructor是析构函数。

pthread_key_delete销毁键,当键销毁后与它关联的数据并没有被销毁!

pthread_setspecific将私有数据与key关联

pthread_getspecific获取私有数据的地址

6. 示例,使用私有数据

/*DATE:2015-4-17 *AUTHOR:WJ *DESCRIPTION:线程到私有数据,一个像errno一样到数据 */#include "apue.h"pthread_key_t key;void *thread_fun1(void *arg){printf("thread 1 start!\n");int a = 1;//将a和key关联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;//将a和key关联pthread_setspecific(key, (void *)a);printf("thread 2 key->data is %d\n", pthread_getspecific(key));}int main(){pthread_t tid1, tid2;//创造一个keypthread_key_create(&key, NULL);//创造新线程if(pthread_create(&tid1, NULL, thread_fun1, NULL)){printf("create new thread 1 failed\n");return;}if(pthread_create(&tid2, NULL, thread_fun2, NULL)){printf("create new thread 2 failed\n");return;}//等待新线程结束pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_key_delete(key);return;}

7. 线程与fork

当线程fork时,为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量、读写锁、条件变量的状态继承过来。如果父进程中互斥量是锁着的,那么子进程中互斥量也是锁着的,虽然子进程自己还没lock。这时,子进程无法解锁。


子进程内部只有一个线程,由父进程中调用fork函数的线程副本构成。如果调用fork的线程将互斥量锁住,那么子进程会拷贝一个pthread_mutex_lock副本。这时子进程就有机会解锁。


pthread_atfork函数

参数prepare在fork调用前会被调用

参数parent在fork返回父进程前调用

参数child在fork返回子进程前调用

8. 示例,线程与fork安全

/*DATE:2015-4-17 *AUTHOR:DDDDD *DESCRIPTION:安全的使用fork *prepare  在调用fork之前会被调用 *parent   在fork返回父进程之前被调用 *child 在fork返回子进程之前被调用 */#include "apue.h"pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void prepare(){pthread_mutex_lock(&mutex);printf("I'm prepare\n");}void parent(){pthread_mutex_unlock(&mutex);printf("I'm parent\n");}void child(){pthread_mutex_unlock(&mutex);printf("I'm child\n");}void *thread_fun(void *arg){sleep(1);pid_t pid;pthread_atfork(prepare, parent, child);pid = fork();if(pid==0){pthread_mutex_lock(&mutex);printf("child process\n");pthread_mutex_unlock(&mutex);}if(pid>0){pthread_mutex_lock(&mutex);printf("parent process\n");pthread_mutex_unlock(&mutex);}}int main(){pthread_t tid;if(pthread_create(&tid, NULL, thread_fun, NULL)){printf("create new thread failed\n");return;}pthread_mutex_lock(&mutex);sleep(2);printf("main\n");pthread_mutex_unlock(&mutex);pthread_join(tid, NULL);pthread_mutex_destroy(&mutex);return;}


注意:线程安全是gcc -pthread 编译

线程非安全是gcc-lpthread编译

0 0
原创粉丝点击