一、清理机制
1、注意
清理机制只能识别到 pthread_exit(NULL) 或者 pthread_cancel() 退出的动作。
如果是return 退出,就不能启动清理函数。
2、函数介绍
函数原型:
void pthread_cleanup_push(void (*routine)(void *),void *arg);
功能:为当前线程注册一个清理函数(在注销pop之前,也就是push和pop之间,如果退出,就会触发清理动作)
参数:
@routine: 指向要注册的清理函数
@arg : 清理函数的参数
函数原型:
void pthread_cleanup_pop(int execute);
功能:注销清理函数
参数:execute: 是否要强制清理
0: 自动清理
1: 强制清理
3、示例
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
//静态初始化互斥锁变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* 线程清理函数 */
void threadClean(void *arg){
printf("启动清理函数--1\n");
free(arg);
pthread_mutex_unlock(&mutex);
}
//线程处理函数
void *thread_handle(void *arg){
pthread_mutex_lock(&mutex); //上锁
void *p = malloc(20); //申请20字节的堆空间
FILE *fp;
/* 注册线程清理函数 */
pthread_cleanup_push(threadClean, p); //调用清理函数
if((fp = fopen("./clean.c", "r")) == NULL){
perror("fopen ");
pthread_exit(NULL);
}
/* 任务代码.... */
/* 注销清理函数 */
//pthread_cleanup_pop(0);
pthread_cleanup_pop(1);
//如果注销清理函数的参数为1的时候,意思为强制清理
//即使注册和注销之间没有退出动作,当运行到注销清理函数的时候也会调用清理函数强制清理
//强制处理的话就可以将下面两行代码:一个释放堆空间 ,一个解锁 这两行省去
//因为不出错也会调用清理函数,不能重复解锁或者是重复释放空间,所以省去。
//pthread_mutex_unlock(&mutex);
//free(p);
fclose(fp);
pthread_exit(NULL);
}
int main()
{
pthread_t tid;
if( pthread_create(&tid, NULL, thread_handle, NULL) ){
perror("create");return -1;
}
pthread_join(tid, NULL);
//如果子线程成功退出,说明锁已经解锁,可以再次上锁验证
pthread_mutex_lock(&mutex);
printf("子线程成功退出\n");
pthread_mutex_unlock(&mutex);
return 0;
}
二、线程属性
一般线程的默认属性是满足使用状态的。
线程属性:
分离状态 = PTHREAD_CREATE_JOINABLE
范围 = PTHREAD_SCOPE_SYSTEM
继承调度程序 = PTHREAD_INHERIT_SCHED
计划策略 = SCHED_OTHER
调度优先级 = 0
保护大小 = 4096 字节
栈地址 = 0x40196000
栈大小 = 0x201000 字节
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_SIZE (1024 * 1024 *10) //1024 * 1024为1M
#define PAGE_SIZE 4096
/* 函数声明 */
void *thread_handle(void *arg);
static void display_pthread_attr(pthread_attr_t *attr);
static void set_pthread_attr(pthread_attr_t *attr);
off_t getFileSize(char *filename);
/* 主函数 */
int main(){
pthread_t tid;
pthread_attr_t my_attr; //定义线程属性
pthread_attr_init(&my_attr); //初始化线程属性(默认)
set_pthread_attr(&my_attr); //设置线程属性
display_pthread_attr(&my_attr); //显示线程属性
if( pthread_create(&tid, &my_attr, thread_handle, NULL) ){
perror("pthread_create ");return -1;
}
void *retval = NULL;
pthread_join(tid, &retval); //如果要接收子线程退出状态,子线程必须为结合态
printf("Thread return : %s\n", (char *)retval);
pthread_attr_destroy(&my_attr); //销毁线程属性
return 0;
}
/* 线程处理函数 */
void *thread_handle(void *arg){
FILE *fp = NULL;
off_t file_size = getFileSize("./Ghost.mp3"); //定义变量存储文件大小
if( file_size > MAX_SIZE){ //判断文件是否大于10M
perror("File Size too big\n");pthread_exit(NULL);
}
unsigned char buffer[MAX_SIZE] = {0}; //申请不会出错, 但是申请的大小最大为8M
unsigned char *tmp = buffer;
size_t readlen; //存放每次读的项数
if( (fp = fopen("./Ghost.mp3","r")) == NULL){
perror("fopen ");
pthread_exit(NULL);
}
while( readlen = (fread(tmp, 1, PAGE_SIZE, fp)) ){
tmp += readlen; //读数据每次读不能都往数组首地址存储,所以要定义临时指针,每次偏移读的字节数
}
printf("Read Over.\n");
fclose(fp);
pthread_exit("Child thread Read Over."); //退出状态返回给主线程
}
/* 显示线程属性 */
void display_pthread_attr(pthread_attr_t *attr){
int i; //分离状态
size_t stack_size; //栈大小
if ( pthread_attr_getdetachstate(attr, &i) ){ /* 获取线程属性--分离状态 */
perror("pthread_attr_getdetachstate");return;
}
printf("Detach state = %s\n",
(i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" :
(i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" :
"???");
if ( pthread_attr_getstacksize(attr, &stack_size) ){ /* 获取线程属性--栈大小 */
perror("pthread_attr_getstacksize");return;
}
printf("Stack Size = 0x%lx\n", stack_size);
}
/*修改线程属性 */
void set_pthread_attr(pthread_attr_t *attr){
if( pthread_attr_setdetachstate(attr, PTHREAD_CREATE_JOINABLE) ){ /* 修改线程属性--分离状态 */
perror("pthread_attr_setdetachstate");return ;
}
if( pthread_attr_setstacksize(attr, 0xb00000) ){ /* 修改线程属性--栈大小 */
perror("pthread_attr_setstacksize");return;
}
}
/* 获取文件大小 */
off_t getFileSize(char *filename){
struct stat a;
if(stat(filename, &a)){
perror("stat");return -1;
}
return a.st_size;
}