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:只在第一個第一個線程進入時執行一次