【C++】Linux多线程开发

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


3.1线程概述

◼ 与进程(process)类似,线程(thread)是允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程。同一个程序中的所有线程均会独立执行相同程序,且共享同一份全局内存区域,其中包括初始化数据段、未初始化数据段,以及堆内存段。(传统意义上的 UNIX 进程只是多线程程序的一个特例,该进程只包含一个线程)
◼ 进程是 CPU 分配资源的最小单位,线程是操作系统调度执行的最小单位。
◼ 线程是轻量级的进程(LWP:Light Weight Process),在 Linux 环境下线程的本质仍是进程。
◼ 查看指定进程的 LWP 号:ps –Lf pid

提示:

◼ 进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用
一些进程间通信方式,在进程间进行信息交换。
◼ 调用 fork() 来创建进程的代价相对较高,即便利用写时复制技术,仍然需要复制诸如
内存页表和文件描述符表之类的多种进程属性,这意味着 fork() 调用在时间上的开销
依然不菲。
◼ 线程之间能够方便、快速地共享信息。只需将数据复制到共享(全局或堆)变量中即可。
◼ 创建线程比创建进程通常要快 10 倍甚至更多。线程间是共享虚拟地址空间的,无需采
用写时复制来复制内存,也无需复制页表。

◼ 共享资源
 进程 ID 和父进程 ID
 进程组 ID 和会话 ID
 用户 ID 和 用户组 ID
 文件描述符表
 信号处置
 文件系统的相关信息:文件权限掩码
(umask)、当前工作目录
 虚拟地址空间(除栈、.text)

◼ 非共享资源
 线程 ID
 信号掩码
 线程特有数据
 error 变量
 实时调度策略和优先级
 栈,本地变量和函数的调用链接信息


提示:以下是本篇文章正文内容,下面案例可供参考

3.2 创建线程

进程:计算机分配资源的最小单位
线程:计算机调度的最小单位

gcc pthread_exit.c -o exit -pthread //第三方库pthread
/*
    #include <pthread.h>

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
            void *(*start_routine) (void *), void *arg);
        -功能:创建一个子线程;一般情况,main函数所在的线程称为主线程(main线程)
                其余创建的线程称为子线程
                程序中默认只有一个进程,fork()函数调用,2个进程
                程序中默认只有一个线程
        -参数:
            thread:传出参数,创建成功的子线程的ID
            attr:设置线程的属性,一般默认值,NULL
            start_routine:函数指针,子线程需要处理的逻辑代码
            arg:给第三个参数使用,传参数
        返回值:
            成功:0
            失败:返回错误号,这个错误号和之前errno不一样
            获取错误号信息:char*  strerror(int errnum) ;

*/
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
void *callback(void *arg){
   
    printf("childthread\n");
    printf("arg value:%d\n",*(int *)arg);
    return NULL;
}

int main(){
   
    pthread_t tid;
    int num =99;
    //创建一个子线程
    int ret=pthread_create(&tid,NULL,callback,(void*)&num);

    if(ret!=0){
   
        char *errstr = strerror(ret);
        printf("error:%s\n",errstr);
    }

    for(int j = 0; j < 10; j++) {
   
        printf("j = %d\n", j);
    sleep(1);
    }

    return 0; // exit(0);
}




3.3、线程终止

/*
    #include <pthread.h>
    void pthread_exit(void *retval);
        功能:终止一个线程,在哪个线程中调用,就表示终止哪个线程
        参数:
            retval:需要传递一个指针,作为一个返回值,可以在pthread_join()中获取
    
    pthread_t pthread_self(void);
        获取当前线程的线程ID

    int pthread_equal(pthread_t t1, pthread_t t2); // 跨平台使用
        比较两个线程ID是否相等
            不同的操作系统,pthread_t的类型不一样,
            有无符号long int, 也有结构体
*/
#include<stdio.h>
#include<pthread.h>
#include<string.h>
void *callback(void *arg){
   
    printf("childthread ID :%ld\n",pthread_self());
    return NULL;//pthread_exit(NULL);
}

int main(){
   
    pthread_t tid;

    //创建一个子线程
    int ret=pthread_create(&tid,NULL,callback,NULL);

    if(ret!=0){
   
        char *errstr = strerror(ret);
        printf("error:%s\n",errstr);
    }

    for(int j = 0; j < 1000; j++) {
   
        printf("j = %d\n", j);
    }

    printf("tid:%ld, mainthread ID :%ld\n",tid,pthread_self());
    
    //退出主线程,但是不会影响其他子线程的运行
    pthread_exit(NULL);

    printf("living?\n");//无法执行
    return 0;//exit(0);
}

3.4连接已经终止线程

/*
    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);
        和已经终止的线程连接进行连接
            回收子线程的资源
            这个函数是阻塞函数,调用一次只能回收一个子线程
            一般在主线程中使用
        
        thread:需要回收的子线程的ID
        retval:接受子线程退出时的返回值

        返回值:
            0:成功
            非0 :失败,返回错误号


*/
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>

int value=10;
void *callback(void *arg){
   
    printf("childthread ID :%ld\n",pthread_self());
    sleep(3);
    //return NULL;//pthread_exit(NULL);
    //int value= 10; 不能返回局部变量,线程结束,栈空间释放,返回随机值
    pthread_exit((void *)&value);//return (void *)&value;
}

int main(){
   
    pthread_t tid;

    //创建一个子线程
    int ret=pthread_create(&tid,NULL,callback,NULL);

    if(ret!=0){
   
        char *errstr = strerror(ret);
        printf("error:%s\n",errstr);
    }

    for(int j = 0; j < 10; j++) {
   
        printf("j = %d\n", j);
    }

    printf("tid:%ld, mainthread ID :%ld\n",tid,pthread_self());
    
    //主线程调用pthread_join()回收子线程资源

    int *thread_retval;
    int re=pthread_join(tid,(void **)&thread_retval);
    //为什么传递二级指针,
    //对int变量的值操作时,要传入一级指针
    //而对int *进行操作,传入二级指针
    if(re!=0){
   
        char *errstr = strerror(ret);
        printf("error:%s\n",errstr);
    }

    printf("exit data:%d\n",*thread_retval);

    printf("回收子线程成功!\n");
    //退出主线程,但是不会影响其他子线程的运行
    pthread_exit(NULL);

    return 0;
}

3.5 线程的分离

/*
    #include <pthread.h>
    int pthread_detach(pthread_t thread);
        分离一个线程,被分离的线程在终止时,会自动释放资源返回系统
        1.不能多次分离,会产生不可预料的行为
        2.不能去连接一个已经分离的线程,会报错
        
        thread:需要分离的线程ID

        返回值:
            成功0;
            失败:返回错误号

*/
#include <pthread.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>

void *callback(void *arg){
   
    printf("child thread ID:%ld\n",pthread_self());
    
  • 54
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值