线程(四):清理机制+线程属性设置

发布于:2024-04-28 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、清理机制

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;
}

网站公告

今日签到

点亮在社区的每一天
去签到