1.线程属性
- 初始化与销毁属性
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
- 获取与设置分离属性
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
设置为JOINABLE,等待线程退出,不至于线程成为僵尸状态
设置为DETACHED,即使线程退出,调用该线程的函数没有调用pthread_join,该线程也不会处于僵尸状态
- 获取与设置栈大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
stacksize默认为0,设置不好,会导致一致性问题
- 获取与设置栈溢出保护区大小
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize);
- 获取与设置线程竞争范围
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
- 获取与设置调度策略
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
- 获取与设置继承的调度策略
int pthread_attr_setinheritsched(pthread_attr_t *attr,
int inheritsched);
int pthread_attr_getinheritsched(const pthread_attr_t *attr,
int *inheritsched);
- 获取与设置调度参数:只关心调度优先级
int pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr,
struct sched_param *param);
- 并发级别:获取与设置并发级别
解释:默认为0,表示内核以自己认为合适的方式进行映射
int pthread_attr_setconcurrency(int new_level);
int pthread_attr_setconcurrency(void);
注意:仅在N:M线程模型中有效,设置并发级别,仅给内核一个提示:表示给定级别数量的核心线程来映射用户线程是高效的。
-
并发级别进一步解释:当前用户线程为3个,给定三个核心线程是高效的(内核),但是多个用户线程对应同一个轻量级进程LWP,这一个轻量级进程又对应一个核心线程,此时并发量不等于5,而后三者是共享一个并发的,所以说只是给内核一个提示,告诉内核以这种映射方式是高效的
-
eg:NetworkProgramming-master (1)\NetworkProgramming-master\P37pthreadattr.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
// written by wangji
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0);
int main(void)
{
pthread_attr_t attr;
pthread_attr_init(&attr);//默认,拥有很多种属性的默认值
int state;
pthread_attr_getdetachstate(&attr,&state);//线程的分离属性的默认值保存在state
if (state == PTHREAD_CREAT_JOINABLE)
printf("detachstate:PTHREAD_CREAT_JOINABLE");
else if (state == PTHREAD_CREAT_DETACHED)
printf("detachstate:PTHREAD_CREAT_DETACHED");
size_t size;
pthread_attr_getstachsize(&attr, &size);
printf("stacksize:%d\n", size);
pthread_attr_getguardsize(&attr, &size);
printf("guardsize:size\n",size);
int scope;
pthread_attr_getscope(&atte, &scope);
if (scope == PTHREAD_SCOPE_PROCESS)//线程的竞争范围在进程内
printf("scope:PTHREAD_SCOPE_PROCESS\n");
if ( scope == PTHREAD_SCOPE_SYSTEM )//线程的竞争范围在系统范围内
printf("scope:PTHREAD_SCOPE_SYSTEM\n");
//线程的调度策略
int policy;
pthread_attr_getschedpolicy(&attr,&policy);
if ( policy == SCHED_FIFO)
printf("policy:SCHED_FIFO\n");//若线程优先级相同,按照陷入先出的方式调度
else if ( policy == SCHED_RR)
printf("policy:SCHED_RR\n");//即使线程优先级相同,抢占式调度
else if ( policy == SCHED_OTHER)
printf("policy:SCHED_OTHER\n");
int inheritsched;
pthread_attr_getinheritsched(&attr, &inheritsched);
if ( inheritsched == PTHREAD_INHERIT_SCHED)//新创建的线程将继承调用者线程的调度策略属性
printf("inheritsched:PTHREAD_INHERIT_SCHED\n");
else if ( inheritsched == PTHREAD_EXPLICIT_SCHED )//表示新创建的线程属性需要自己设置,由setschedpolicy设置
printf("inheritsched:PTHREAD_EXPLICIT_SCHED\n");
struct sched_param param;
pthread_attr_getschedparam(&attr, ¶m);
printf("sched priority:%d\n", param.sched_priority);
pthread_attr_destroy(&attr);
int level;
level = pthread_getconcurrency();//并发级别
printf("level:%d\n", level);
return 0;
}
- 测试结果:
2.线程特定数据
-
在单线程程序中,我们经常要用到全局变量以实现多个函数间共享数据
-
在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所公有
-
但有时应用程序中有必要提供线程私有的全局变量,仅仅在某个线程中有效,但却可以跨多个函数访问
-
POSIX线程库通过维护一定的数据结构来解决这个问题,这些个数据称之为(Thread-specific Data,或者TSD)
-
示例图如下:
(1)每个线程都有特定数据128项,也就是都有128个key,以key->value形式来组织的。
(2)若线程0创建key1,则其它线程也会得到key1。相当于两个线程都具有a的全局变量。但是每个线程都指向自己的数据a,并不是指向同一个内存。
(3)线程0对a改变,并不会影响到线程n
-
线程特定数据的函数
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
pthread_once:只在第一个第一个线程进入时执行一次
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
pthread_once_t once_control=PTHREAD_ONCE_INIT;
- eg1:NetworkProgramming-master (1)\NetworkProgramming-master\P37thread.c
//
// Created by wangji on 19-8-14.
//
// p37 poxis 线程(二)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
using namespace std;
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0);
struct tsd
{
pthread_t id;
char* arg;
}tsd_t;
pthread_key_t thread_key;//全局的TSD数据key
pthread_once_t once = PTHREAD_ONCE_INIT;
void destr_function(void *)
{
printf("destroy...\n");
free(value);
}
void once_run(void)
{
pthread_key_create(&thread_key, destr_function);
// cout<<"once_run in thread "<<(unsigned int )pthread_self()<<endl;
printf("key init ... \n");
}
void * start_routine (void *arg)
{
// pthread_once(&once, once_run);//只在第一个第一个线程进入时执行once_run,意味着key只创建1次
tsd_t *value = (tsd_t*)malloc(sizeof(tsd_t));
value->arg = (char *)arg;
value->id = pthread_self();tsd_t
//给线程设定特定数据
pthread_setspecific(thread_key, value);
printf("%s setspecific %p\n", (char*)arg, value);
value = (struct tsd_t*)pthread_getspecific(thread_key);
printf("tid = 0x%x str = %s\n", (int)value->id, value->arg);//打印线程ID和str
sleep(2);
value = (struct tsd_t*)pthread_getspecific(thread_key);
printf("tid = 0x%x str = %s\n", (int)value->id, value->arg);
return NULL;
}
int main(int argc, char** argv) {
//thread_key:key是每个线程的全局变量,但是key指向的变量是每个线程所独享的
//每个线程都有thread_key变量
//destr_function主要是用来销毁key所指向的value的数据的
//当下面2个线程退出时,都会执行destr_function销毁数据,即执行2次
pthread_key_create(&thread_key, destr_function);
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, start_routine, (char *)"thread1");
pthread_create(&thread2, NULL, start_routine, (char *)"thread2");
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//当两个线程退出时,删除key
pthread_key_delete(thread_key);
return 0;
}
-
测试结果:
-
eg2:NetworkProgramming-master (1)\NetworkProgramming-master\P37thread.c
使用pthread_once
//
// Created by wangji on 19-8-14.
//
// p37 poxis 线程(二)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
using namespace std;
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0);
struct tsd
{
pthread_t id;
char* arg;
}tsd_t;
pthread_key_t thread_key;//全局的TSD数据key
pthread_once_t once = PTHREAD_ONCE_INIT;
void destr_function(void *)
{
printf("destroy...\n");
free(value);
}
void once_run(void)
{
pthread_key_create(&thread_key, destr_function);
// cout<<"once_run in thread "<<(unsigned int )pthread_self()<<endl;
printf("key init ... \n");
}
void * start_routine (void *arg)
{
pthread_once(&once, once_run);//只在第一个第一个线程进入时执行once_run,意味着key只创建1次
tsd_t *value = (tsd_t*)malloc(sizeof(tsd_t));
value->arg = (char *)arg;
value->id = pthread_self();tsd_t
//给线程设定特定数据
pthread_setspecific(thread_key, value);
printf("%s setspecific %p\n", (char*)arg, value);
value = (struct tsd_t*)pthread_getspecific(thread_key);
printf("tid = 0x%x str = %s\n", (int)value->id, value->arg);//打印线程ID和str
sleep(2);
value = (struct tsd_t*)pthread_getspecific(thread_key);
printf("tid = 0x%x str = %s\n", (int)value->id, value->arg);
return NULL;
}
int main(int argc, char** argv) {
//thread_key:key是每个线程的全局变量,但是key指向的变量是每个线程所独享的
//每个线程都有thread_key变量
//destr_function主要是用来销毁key所指向的value的数据的
//当下面2个线程退出时,都会执行destr_function销毁数据,即执行2次
// pthread_key_create(&thread_key, destr_function);
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, start_routine, (char *)"thread1");
pthread_create(&thread2, NULL, start_routine, (char *)"thread2");
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//当两个线程退出时,删除key
pthread_key_delete(thread_key);
return 0;
}
- 测试结果:
- Makefile文件
.PHONY=clean all
CFLAGS=-Wall -g
CC=gcc
BIN=threadattr tsd
all:$(BIN)
%.o:%c
$(CC) $(CFLAGS) -c $< -o $@
threadattr:threadattr.o
$(CC) $(CFLAGS) $^ -o $@ -lpthread
tsd:tsd.o
$(CC) $(CFLAGS) $^ -o $@ -lpthread
clean:
rm -f $(BIN) *.o
设置为JOINABLE,等待线程退出,不至于线程成为僵尸状态
设置为DETACHED,即使线程退出,调用该线程的函数没有调用pthread_join,该线程也不会处于僵尸状态
stacksize默认为0,设置不好,会导致一致性问题
只关心调度优先级
默认为0,表示内核以自己认为合适的方式进行映射
表示:当前用户线程为3个,给定三个核心线程是高效的(内核),但是多个用户线程对应同一个轻量级进程LWP,这一个轻量级进程又对应一个核心线程,此时并发量不等于5,而后三者是共享一个并发的,所以说只是给内核一个提示,告诉内核以这种映射方式是高效的
每个线程都有特定数据128项,也就是都有128个key,以key->value形式来组织的。
若线程0创建key1,则其它线程也会得到key1。相当于两个线程都具有a的全局变量。但是每个线程都指向自己的数据a,并不是指向同一个内存。
线程0对a改变,并不会影响到线程n
once:只在第一个第一个线程进入时执行一次