多线程API - 小白如何快速上手并发编程

多线程API - 小白如何快速上手并发编程

  • 线程的基本概念

    • 一.线程和进程的区别(linux环境下)
      • 进程是资源管理的最小单位,线程是系统执行的最小单位
      • 线程和进程都有对应的PCB和TCB,在linux内核中创建线程和进程使用的底层函数和进程一样,都是clone
      • 进程可以蜕化成线程,一个进程可以有一个至多个线程
      • 进程有自己独享的0-4G虚拟地址空间,而线程共享同一进程的地址空间
    • 二.线程有共享也有独占
      • 线程共享的资源有:
        • 1.文件描述符表
        • 2.每种信号的处理方式
        • 3.当前工作目录
        • 4.用户ID和组ID
        • 5.内存地址空间 (.text/.data/.bss/heap/共享库)
      • 线程独占的资源有:
        • 1.线程id
        • 2.计数器和栈空间(内核栈和用户空间栈)
        • 3.信号屏蔽字
        • 4.errno变量
        • 5.调度优先级
    • 三.线程的优缺点
      • 优点
        • 1.提高程序并发性
        • 2.开销小
        • 3.数据通信、共享数据方便
      • 缺点
        • 1.线程所有操作函数 pthread_* 是库函数,而非系统调用,不够稳定
        • 2.编写调试困难,不支持gdb
        • 3.对信号支持性差
  • 使用线程的API

    • 线程常见的函数有以下几种
      • pthread_self函数 - 获取线程id
      • pthread_create函数 - 创建一个新线程
      • pthread_exit函数 - 将单个线程退出
      • pthread_join函数 - 阻塞等待线程退出并获取线程退出状态
      • pthread_cancel函数 - 杀死(取消)线程
      • pthread_detach函数 - 实现线程分离
      • pthread_equal函数 - 比较线程id是否相等(系统留用,看以后pthread_t是否改为结构体)
    • 线程API和进程API对比
      • pthread_self - getpid
      • pthread_create - fork
      • pthread_exit - exit
      • pthread_join - wait
      • pthread_cancel - kill
  • 线程控制原语

    • pthread_t pthread_self(void); ---------使用见线程实例1

      • 功能 : 获取线程id

      • 返回值:成功:0; 失败:NULL

        • 线程ID:pthread_t类型,本质:在Linux下为无符号整数(%lu),可以理解为typedef unsigned long int pthread_t;

        • notes

          • 线程id是进程内识别不同线程的标志,也意味着两个进程间有允许使用相同的线程id

          • 在获取线程id时,避免使用全局变量。在主线程可通过pthread_create第一个参数传出,在子线程通过调用pthread_self()得到id.

      • int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -----使用见线程实例1

        • 功能 :创建一个新线程

        • 返回值:成功:0; 失败:错误号 -----Linux环境下,所有线程特点,失败均直接返回错误号。

        • parameters

          • 参数1:传出参数,保存系统为我们分配好的线程ID

            • 参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。

            • 参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。

            • 参数4:线程主函数执行期间所使用的参数==,若线程需要多个参数,可传入结构体变量==

      • void pthread_exit(void *retval); ------ 使用见线程实例3

        • 功能 : 将单个线程退出

        • parameter

          • retval表示线程退出状态,通常传NULL
        • notes

          • 不能使用exit退出指定的线程,因为exit是退出进程的,会将该进程所有线程退出

          • 线程的三种退出方式

            • return
            • pthread_exit()
            • pthread_cancel()
    • int pthread_join(pthread_t thread, void **retval); ------使用见线程实例4

      • 功能 : 阻塞等待线程退出并获取线程退出状态

      • parameters

        • 参数1 : 需要等待的线程id
        • 参数2 : 获取线程id退出状态
      • notes

        • 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值.

        • 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED(一般为-1)。

        • 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传pthread_exit的参数

        • 如果对线程退出状态没有兴趣,可以对retval传空。

    • int pthread_cancel(pthread_t thread); ------使用见线程实例4

      • 功能 : 杀死(取消)线程

      • 成功:0;失败:错误号

      • notes

        • 线程取消不是立马执行的,需要一定的时间。需要线程进入系统调用creat,open,pause,close,read,write等,才可退出,若线程中没有系统调用,需要添加pthread_testcancel()函数断点,否则线程死循环
    • int pthread_detach(pthread_t thread); ------使用见线程实例5

      • 功能 : 实现线程分离

      • 返回值:0;失败:错误号

      • notes

        • 分离态线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态,避免僵尸线程。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误(一般为22)。
    • int pthread_equal(pthread_t t1, pthread_t t2);//几乎不用

      • 功能 : 获取线程id

  • 线程实例

    • 1.创建一个子线程,子线程打印出自己的线程id

      #include <stdio.h>
      #include <unistd.h>
      #include <pthread.h>
      
      void *thread1(void *arg)
      {
              printf("my thread_id is %lu\n",pthread_self());
              return NULL;
      }
      
      int main(int args, char *argv[])
      {
              pthread_t tid;//pthread is equal to unsigned long in linux
      
              pthread_create(&tid, NULL, thread1, NULL);//第一个NULL表示默认属性,第二个是线程执行时所需要的参数
              sleep(1);//wait thread end
      
              return 0;
      }
      
      • 编译

      在这里插入图片描述

      • 运行

      在这里插入图片描述

    • 2.循环创建多个子线程,并使用pthread_exit退出其中i = 3的线程

      #include <stdio.h>
      #include <unistd.h>
      #include <pthread.h>
      
      void *thread(void *arg)
      {
              int i = 0;
              i = (int)arg;
      
              if(3 == i)//3 thread exit
              {
                      pthread_exit(NULL);
              }
              sleep(i);//keep thread write order
              printf("I am %d thead, my thread id is %lu\n", i, pthread_self());
      
      }
      
      int main(int args, char *arg[])
      {
              pthread_t tid = 0;
              int i = 0;
      
              for(i=0; i<5; i++)
              {
                      pthread_create(&tid, NULL, thread, (void*)i);
              }
              sleep(i);//wait thread end
      
              return 0;
      }
      
      
      • 编译

      在这里插入图片描述

      • 运行

      在这里插入图片描述

    • 3.创建多个线程并使用pthread_exit退出,打印出join保存的线程退出状态

      #include <stdio.h>
      #include <unistd.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      typedef struct node
      {
              int a;
              int b;
      }LNODE;
      
      void *thread(void *arg)
      {
              LNODE *node1;
              node1 = (LNODE*)malloc(sizeof(struct node));
              if(NULL == node1)
              {
                      printf("no enough memory malloc\n ");
                      return NULL;
              }
      
              node1->a = 100;
              node1->b = 200;
      
              pthread_exit((void *)node1);//如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数
      }
      
      int main(int args,char *argv[])
      {
              pthread_t tid = 0;
              LNODE *node2 = NULL;
      
              pthread_create(&tid, NULL, thread, NULL);
              pthread_join(tid, (void**)&node2);
              printf("node->a is %d, node->b = %d\n", node2->a, node2->b);
      
              free(node2);
              node2 = NULL;
      
              return 0;
      }
      
      
      • 编译

      在这里插入图片描述

      • 运行

      在这里插入图片描述

    • 4.创建三个进程,分布使用不同的退出方式进行测试(return, pthread_exit, pthread_cancel)

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      int *thread1(void *arg)//return
      {
              printf("I am thread1, my tid is %lu\n", pthread_self());
      
              return 111;
      }
      
      void *thread2(void *arg)//pthread
      {
              printf("I am thread2, my tid is %lu\n", pthread_self());
      
              pthread_exit((void *)222);
      }
      
      void *thread3(void *arg)//cancel
      {
              int i = 0;
              while(1)
              {
                      i++;
                      pthread_testcancel();
              }
      
              return (void *)333;
      }
      
      int main(int args, char *argv[])
      {
              pthread_t tid = 0;
              void *pointer = NULL;
      
              pthread_create(&tid, NULL, (void *)thread1, NULL);
              pthread_join(tid, &pointer);
              printf("thread1 return value is %d\n", (int)pointer);
      
              pthread_create(&tid, NULL, thread2, NULL);
              pthread_join(tid, &pointer);
              printf("thread2 return value is %d\n", (int)pointer);
      
              pthread_create(&tid, NULL, thread3, NULL);
              pthread_cancel(tid);
              pthread_join(tid, &pointer);
              printf("thread3 return value is %d\n", (int)pointer);
      
              return 0;
      }
      
      • 编译

      在这里插入图片描述

      • 运行

        • thread增加取消点,线程退出

          在这里插入图片描述

        • thread3不增加取消点(code_line25 //pthread_testcancel()),线程死锁

          在这里插入图片描述

    • 5.设置线程为detach游离态,使用pthread_join判断线程退出状态

      #include <stdio.h>
      #include <unistd.h>
      #include <pthread.h>
      
      void *thread(void *arg)
      {
      
              printf("I am thread, my tid is %lu\n", pthread_self());
      
              pthread_exit((void *)111);
      }
      
      int main(int args, char *argv[])
      {
              pthread_t tid = 0;
              int error_flag = 0;
              void *status_pointer = NULL;
      
              pthread_create(&tid, NULL, thread, NULL);
              pthread_detach(tid);
              error_flag = pthread_join(tid, &status_pointer);
              printf("thread value is %d\n", (int)status_pointer);
              printf("error_flag is %d\n", error_flag);
      
              return 0;
      }
      
      • 编译

      在这里插入图片描述

      • 运行
    • line21将线程分离,可见detach后,线程退出后自动回收,其状态无法再用join获得

      在这里插入图片描述

    • line21注释,保持线程combination,正常获取线程状态111

      在这里插入图片描述

原创文章 7 获赞 13 访问量 4580

猜你喜欢

转载自blog.csdn.net/MOSHIWANGJUE/article/details/105856327
今日推荐