加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

pthread

发布时间:2020-12-14 01:34:50 所属栏目:Linux 来源:网络整理
导读:目录 基础API pthread_self pthread_create pthread_exit pthread_join pthread_detach pthread_cancel pthread_equal 线程属性的设置 使用注意事项 实例程序 pthread_create使用 传值与传地址 主线程先退出 join与pthread_exit 两个线程数 使用pthread_canc

目录

  • 基础API
    • pthread_self
    • pthread_create
    • pthread_exit
    • pthread_join
    • pthread_detach
    • pthread_cancel
    • pthread_equal
    • 线程属性的设置
  • 使用注意事项
  • 实例程序
    • pthread_create使用
    • 传值与传地址
    • 主线程先退出
    • join与pthread_exit
    • 两个线程数
    • 使用pthread_cancel杀死分离的线程

基础API

头文件: #include <pthread.h>

失败返回错误号,不能用perror打印错误信息,使用strerror(ret)

pthread_self

pthread_t pthread_self(void);
返回线程ID,在linux下是无符号整数(%lu),在其他系统中可能是结构体实现
线程ID是内部标识,两个进程间,线程ID可以相同

pthread_create

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine) (void *),void *arg);
创建线程: pthread_create,函数调用成功返回0,
参数:
  thread: 传出参数,保存系统分配的ID
  attr: 线程属性,通常传NULL. 默认父子进程不分离,主线程要手动释放子进程pcb,即使用pthread_join
  stat_routine: 子线程的处理函数
  arg: 回调函数的参数

pthread_exit

void pthread_exit(void *retval);
单个线程退出,主线程执行pthread_exit不影响子线程的执行
主线程执行exit或return,则子线程都会退出
子线程执行exit,所有线程(包括主线程)都会推出
子线程执行return和pthread_exit都是退出当前线程

参数:
  retval: 必须指向全局或堆的地址空间,不能是一个栈地址

pthread_join

int pthread_join(pthread_t thread,void **retval);
阻塞等待线程退出,获取线程退出状态
参数:
  thread: 要回收的子线程的线程id,不是指针
  reval: 读取线程退出的时候携带的状态信息,指向的内存和pthread_exit或return参数指向的内存一样; 如果线程使用pthread_cancel异常终止,reval所指向的单元里存放常数PTHREAD_CANCELED

pthread_detach

int pthread_detach(pthread_t thread); 线程分离
调用该函数之后不需要pthread_join,子线程会自动回收自己的pcb,一般在创建线程时设置分离属性

pthread_cancel

int pthread_cancel(pthread_t thread); 杀死(取消)线程,可杀死分离的线程
使用注意事项: 在要杀死的子线程对应的处理的函数的内部,必须做过一次系统调用(使用类似printf的函数),即不是实时的杀死线程; 可以使用pthread_testcancel()来添加取消点

pthread_equal

int pthread_equal(pthread_t t1,pthread_t t2);
比较两个线程ID是否相等(预留函数)

线程属性的设置

通过属性设置线程的分离
线程属性类型: pthread_attr attr;
线程属性操作函数
  int pthread_attr_init(pthread_attr_t *attr);
对线程属性变量的初始化
  int pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate); 设置线程分离属性
    attr: 线程属性
    detachstate: PTHREAD_CREATE_DETACHED(分离),PTHREAD_CREATE_DETACHED(非分离)
  int pthread_attr_destroy(pthread_attr_t *attr); 释放线程资源

使用注意事项

  1. 主线程退出其他线程不退出,主线程应调用pthread_exit
  2. 避免僵尸线程: pthread_join,pthread_detach,pthread_create指定分离属性
  3. malloc和mmap申请的内存可以被其他线程释放
  4. 应避免在多线程模型中调用fork,除非马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit-->不太懂
  5. 信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制

实例程序

pthread_create使用

输出顺序不确定

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

void *myfunc(void * arg) {
    // 打印子线程ID
    printf("child thread id: %ludn",pthread_self());
    return NULL;
}

int main(int argc,const char * argv[]) {
    // 创建一个子线程
    // 线程ID对应的变量
    pthread_t pthid;
    pthread_create(&pthid,NULL,myfunc,NULL);
    printf("parent thread id: %ludn",pthread_self());

    for (int i = 0; i < 5; i++) {
        printf("i = %dn",i);
    }

    sleep(2);   

    return 0;
}

传值与传地址

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

void *myfunc(void *arg) {
    //int num = *(int*)arg;
    int num = (int)arg;
    
    // 打印子线程ID
    printf("%dth child thread id: %lun",num,pthread_self());
}

int main(void) {
    pthread_t pthid[5];
    int i;

    for (i = 0; i < 5; i++) {
        //pthread_create(&pthid[i],(void*)&i);
        // 由于int存储空间和指针的存储空间相同所以可以这么传 
        pthread_create(&pthid[i],(void*)i);  
    }
    printf("parent thread id: %lu",pthread_self());

    for (i = 0; i < 5; i++)         // 子线程不会执行接下来的for循环
        printf("i = %dn",i);

    sleep(2);

    return 0;
}

主线程先退出

主线程先退出,子线程正常执行

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

void *myfunc(void *arg) {
    printf("child pthread id: %lun",pthread_self());
    printf("child thread .....n");
    int i;
    for (i = 0; i < 3; i++) 
        printf("child i = %dn",i);
    
    //return NULL;
}

int main(void) {
    int i;
    pthread_t thid;
    int ret = pthread_create(&thid,NULL);

    if (ret != 0) {
        printf("error number: %dn",ret);
        printf("error information: %sn",strerror(ret));
    }
    printf("parent pthread id: %lun",pthread_self());

    // 退出主线程,子线程不受影响
    pthread_exit(NULL);

    printf("parent thread .....n");
    for (i = 0; i < 3; i++) 
        printf("i = %dn",i);

    return 0;
}

/*
parent pthread id: 139948367210304
child pthread id: 139948358948608
child thread .....
child i = 0
child i = 1
child i = 2
*/

join与pthread_exit

没有return返回和return NULL结果一样都是core dumped
使用return &numberpthread_exit(&number)时,主线程的pthread_join(thid,(void**)&ptr);都可以收到number的值

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

int number = 100;

void *myfunc(void *arg) {
    printf("child pthread id: %lun",pthread_self());
    printf("child thread .....n");
    number++;
    int i;
    for (i = 0; i < 3; i++) 
        printf("child i = %dn",i);

    // return NULL;     // Segmentation fault (core dumped)
    //return &number;
    pthread_exit(&number);
}

int main(void) {
    int i;
    pthread_t thid;
    int ret = pthread_create(&thid,pthread_self());

    int *ptr;
    // 阻塞等待子线程的结束,并回收pch
    pthread_join(thid,(void**)&ptr);
    printf("++++++ number = %dn",*ptr);

    printf("parent thread .....n");
    for (i = 0; i < 3; i++) 
        printf("i = %dn",i);

    return 0;
}

/*
parent pthread id: 139819023099712
child pthread id: 139819014838016
child thread .....
child i = 0
child i = 1
child i = 2
++++++ number = 101
parent thread .....
i = 0
i = 1
i = 2

*/

两个线程数

当线程A数的数字还没有写入内存中时,就已经失去cpu
当线程B数的数字同步到内存中时,会导致共享的数据混乱

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

#define MAX 1000
// 全局变量
 int number;

 // 线程处理函数
void* funcA_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        int cur = number;
        cur++;
        number = cur;
        printf("Thread A,id = %lu,number = %dn",pthread_self(),number);
        usleep(10);
    }

    return NULL;
}

void* funcB_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        int cur = number;
        cur++;
        number = cur;
        printf("Thread B,number);
        usleep(10);
    }

    return NULL;
}

int main(int argc,const char* argv[])
{
        pthread_t p1,p2;

        // 创建两个子线程
        pthread_create(&p1,funcA_num,NULL);
        pthread_create(&p2,funcB_num,NULL);

        // 阻塞,资源回收
        pthread_join(p1,NULL);
        pthread_join(p2,NULL);

        return 0;
}
/*
number可能数的数字不足
*/

使用pthread_cancel杀死分离的线程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>

void* myfunc(void* arg)
{
        printf("child pthread id: %lun",pthread_self());

        while (1) {
            printf("hahan");
            sleep(2);
        }

        return NULL;
            
}

int main(int argc,const char* argv[])
{
    pthread_t thid;
    // 初始化线程属性
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    // 返回错误号
    int ret = pthread_create(&thid,&attr,NULL);
    if(ret != 0)
    {
        printf("error number: %dn",ret);
        // 根据错误号打印错误信息
        printf("error information: %sn",pthread_self());

    pthread_cancel(thid);
    sleep(1);

    pthread_attr_destroy(&attr);
    pthread_exit(NULL);
    //return 0;
}
/*
parent pthread id: 140625550829376
child pthread id: 140625542567680
haha
*/

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读