• Linux应用开发 - 多线程编程


    Linux应用开发 - 多线程编程

    定义

    线程是进程中的一个独立的代码块。说白了,其实它就是个函数,只不过再也不用像以前的函数调用来调用它。而是通过pthread_create函数来创建它,也就是告诉内核,这个函数是个线程,今后交给你来调度了。

    相关API

    //创建线程 
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 
    //退出线程 
    void pthread_exit(void *retval); 
    //回收线程 
    int pthread_join(pthread_t thread, void **retval); 
    //分离线程 
    int pthread_detach(pthread_t thread); 
    //取消线程 
    int pthread_cancel(pthread_t thread); 
    //获取本线程的ID 
    pthread_t pthread_self(void); 
    //判断两个线程id是否相等 
    int pthread_equal(pthread_t t1, pthread_t t2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    案例1

    创建线程

    #include 
    #include 
    #include 
    #include 
    
    void *fun(void *arge)
    {
        printf("pthread new = %lu\n",(unsigned int)pthread_self());
    }
    
    int main(void)
    {
        pthread_t tid1;
        int ret = pthread_create(&tid1,NULL,fun,NULL);
        if (ret!=0)
        {
            perror("pthread error\n");
            return -1;
            /* code */
        }
        printf("tid_main=%lu tid_new=%lu\n",(unsigned int)pthread_self(),tid1); // tid1标识线程创建成功后指向的空间
        sleep(1);//为了等会儿子线程 要不主线程一执行完就结束了
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这个案例仅是用于在主进程中创建一个线程

    线程函数的程序在 pthread 库中,故链接时要加上参数 -lpthread。

    运行结果:

    tid_main=1999865600 tid_new=140696530216704
    pthread new = 1991534336

    函数说明:

    int pthread_create( pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void ( func) (void *), void *restrict arg )

    • thread:线程标识符
    • attr: 线程属性设置 null表示采用默认
    • start_roitine : 线程函数的启示地址、
    • arg :传递给start_routine的参数
    • 返回值:成功:0出错:-1

    案例2

    线程传参

    #include 
    #include 
    #include 
    #include 
    
    struct student
    {
        int age;
        char name[20];
        /* data */
    };
    
    
    void *fun(void *stu)
    {
        printf("pthread new = %lu\n",(unsigned int)pthread_self());
        printf("name:%s\tage:%d\n",((struct student *)stu)->name,((struct student *)stu)->age);
    }
    
    int main(void)
    {
        struct student stu;
        stu.age = 10;
        memcpy(stu.name,"liming",6);
    
        pthread_t tid1;
        int ret = pthread_create(&tid1,NULL,fun,(void *)&stu);
        if (ret!=0)
        {
            perror("pthread error\n");
            return -1;
            /* code */
        }
        printf("tid_main=%lu tid_new=%lu\n",(unsigned int)pthread_self(),tid1); // tid1标识线程创建成功后指向的空间
        sleep(1);//为了等会儿子线程 要不主线程一执行完就结束了
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行结果:

    tid_main=3901490944 tid_new=140084251518720
    pthread new = 3893159680
    name:liming age:10

    案例3

    线程退出

    终止线程执行(3种方法)

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    void *thread_fun(void *args)
    {
        if (strcmp("1", (char *)args) == 0)
        {
            printf("new thread return\n");
            return (void *)1;
            /* code */
        }
        if (strcmp("2", (char *)args) == 0)
        {
            printf("new thread pthread_exit\n");
            pthread_exit((void *)2);
            /* code */
        }
        if (strcmp("3", (char *)args) == 0)
        {
            printf("new thread exit\n");
            exit(3);
        }
    }
    
    int main(int argc, char *argv[])
    {
        int err;
        pthread_t tid;
        err = pthread_create(&tid, NULL, thread_fun, (void *)argv[1]);
        if (err != 0)
        {
            printf("creat thread fail\n");
            return 0;
        }
        sleep(1);
        printf("main func\n");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    运行结果:

    ./exit1 1

    new thread return
    main func

    return的作用是:返回到调用者处。有可能会退出进程(放在主线程时),有可能会退出线程,也有可能什么也不退出。

    ./exit1 2

    new thread pthread_exit
    main func

    只退出当前子线程。注意:在主线程退出时,其它线程不会结束。同样可以执行。所以这个只字非常重要。并且,与return一样,pthread_exit退出的线程也需要调用pthread_join去回收子线程的资源(8k左右),否则服务器长时间运行会浪费资源导致无法再创建新线程。

    ./exit1 3

    new thread exit

    将进程退出,无论哪个子线程调用整个程序都将结束。

    案例4

    线程回收

    #include 
    #include 
    //定义线程要执行的函数,arg 为接收线程传递过来的数据
    void* Thread1(void* arg)
    {
        printf("hello linux\n");
        return "Thread1成功执行";
    }
    //定义线程要执行的函数,arg 为接收线程传递过来的数据
    void* Thread2(void* arg)
    {
        printf("李魁\n");
        return "Thread2成功执行";
    }
    
    int main()
    {
        int res;
        //创建两个线程变量 
        pthread_t mythread1, mythread2;
        void* thread_result;
        //创建 mythread1 线程,执行 Thread1() 函数
        res = pthread_create(&mythread1, NULL, Thread1, NULL);
        if (res != 0) {
            printf("线程创建失败");
            return 0;
        }
        //创建 mythread2 线程,执行 Thread2() 函数
        res = pthread_create(&mythread2, NULL, Thread2, NULL);
        if (res != 0) {
            printf("线程创建失败");
            return 0;
        }
        //阻塞主线程,直至 mythread1 线程执行结束,用 thread_result 指向接收到的返回值,阻塞状态才消除。
        res = pthread_join(mythread1, &thread_result);
        //输出线程执行完毕后返回的数据
        printf("%s\n", (char*)thread_result);
        //阻塞主线程,直至 mythread2 线程执行结束,用 thread_result 指向接收到的返回值,阻塞状态才消除。
        res = pthread_join(mythread2, &thread_result);
        printf("%s\n", (char*)thread_result);
        printf("主线程执行完毕");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    运行结果:

    hello linux
    李魁
    Thread1成功执行
    Thread2成功执行
    主线程执行完毕

    int pthread_join(pthread_t thread, void ** retval);

    函数功能:

    • 接收目标线程执行结束时的返回值
    • 释放目标线程占用的进程资源

    thread 参数用于指定目标线程;retval 参数用于存储接收到的返回值。实际场景中,调用 pthread_join() 函数可能仅是为了及时释放目标线程占用的资源,并不想接收它的返回值,这种情况下可以将 retval 置为 NULL。

    函数会一直阻塞当前线程,直至目标线程执行结束,阻塞状态才会消除。如果成功等到了目标线程执行结束(成功获取到目标线程的返回值)函数返回数字 0,否则返回非零数。

    • 程序中共有 3 个线程,分别是主线程,mythread1 线程和 mythread2 线程。mythread1 线程负责执行 Thread1() 函数,mythread2 线程负责执行 Thread2() 函数。
    • 主线程先后调用了两次 pthread_join() 函数,都会阻塞主线程,直至 mythread1 和 mythread2 线程执行完毕,阻塞状态才会消除。
  • 相关阅读:
    Spring Boot 面试题及答案整理,最新面试题
    白银现货K线走势图分析
    第四章 排序 6 AcWing 1538. 链表排序
    论文阅读笔记(四)——实例分割与掩模R-CNN应用于多摄像机设置中松散的奶牛
    Rockland蛋白质印迹试剂丨Rockland SDS-PAGE脱色液
    JavaScript学习笔记04
    vc版本与vs版本对应关系
    C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
    PyPDF2 模块抽取PDF文件部分页面另存新文档
    Go ZIP压缩文件读写操作
  • 原文地址:https://blog.csdn.net/qq_41470744/article/details/128028082