zoukankan      html  css  js  c++  java
  • Linux pthread 线程 浅解

    线程

    1. 问题
      使用fork创建进程以执行新的任务,该方式的代价很高。

      解决办法:使用线程

    2. 什么是线程
      线程,是进程内部的一个控制序列。
      即使不使用线程,进程内部也有一个执行线程。

      类比:创建一个进程,类似于“克隆”一个家庭。
      该“家庭”与原来的家庭完全相同
      但是新“家庭”和原来的家庭完全独立。

          进程包含一个或多个线程。
          类似与一个家庭,包含一个或多个家庭成员。
           家庭内的各成员同时做各自的事情(父亲工作、母亲持家、小孩上学)
           而对于家庭外部的人来说,这个家庭同时在做多件事情。
      
           家庭内的每个成员,就是一个线程。
           各个家庭成员有自己的个人资源(线程有自己的局部变量)
           但是所有家庭成员都能共享这个家庭的资源:房子、汽车、家庭的公共资金。
           (同一个进程内的各个线程,能够共享整个进程的全局变量,除了线程的局部变量外,其他资源都共享)
      

      注意:单核处理器上,同一个时刻只能运行一个线程。
      但是对于用户而言,感觉如同同时执行了多个线程一样
      (各线程在单核CPU上切换,在一段时间内,同时执行了多个线程)

    3. 线程的优点、缺点
      优点: 创建线程比创建进程,开销要小。
      缺点: 1)多线程编程,需特别小心,很容易发生错误。
      2)多线程调试很困难。
      3)把一个任务划分为两部分,
      用两个线程在单处理器上运行时,不一定更快。
      除非能确定这两个部分能同时执行、且运行在多处理器上。

    4. 线程的应用场合
      1) 需要让用户感觉在同时做多件事情时,
      比如,处理文档的进程,一个线程处理用户编辑,一个线程同时统计用户的字数。

      2) 当一个应用程序,需要同时处理输入、计算、输出时,
      可开3个线程,分别处理输入、计算、输出。
      让用户感觉不到等待。

    5. 线程的使用
      1)线程的创建
      pthread_create
      原型:int pthread_create (
      pthread_t *thread,
      pthread_attr_t *attr,
      void (*start_routine)(void),
      void *arg);

      参数:thread, 指向新线程的标识符。
      通过该指针返回所创建线程的标识符。
      attr, 用来设置新线程的属性。
      一般取默认属性,即该参数取NULL
      start_routine, 该线程的处理函数
      该函数的返回类型和参数类型都是void*
      arg, 线程处理函数start_routine的参数

      功能:创建一个新线程,
      同时指定该线程的属性、执行函数、执行函数的参数
      通过参数1返回该线程的标识符。

      返回值:成功,返回0
      失败,返回错误代码
      注意:大部分pthread_开头的函数成功时返回0,失败时返回错误码(而不是-1)

      注意:使用fork创建进程后,进程 马上就启动,但是是和父进程同时执行fork之后后的代码。
      使用pthread_create创建线程后,新线程马上就启动,即执行对应的线程处理函数。

      2)线程的终止
      pthread_exit
      原型:void pthread_exit (void *retval)
      功能:在线程函数内部调用该函数。
      终止该线程,并通过参数retval返回一个指针。
      该指针不能指向该线程的局部变量。

      3)等待指定线程结[
      pthread_join
      功能:类似与进程中的waitpid
      等待指定的线程结束,并使参数指向该线程函数的返回值(用pthread_exit返回的值)
      原型:int pthread_join (pthread_t th,
      void ** thread_return);
      参数:th, 指定等待的线程
      thread_return, 指向该线程函数的返回值
      线程函数的返回值类型为void*,故该参数的类型为void**

      4)使用线程程序的编译
      (1) 编译时,定义宏_REENTRANT
      即: gcc -D_REENTRANT (#define REENTRANT)

             功能:告诉编译器,编译时需要可重入功能。
                     即使得,在编译时,编译部分函数的可重入版本。
      
       (2) 编译时,指定线程库
            即: gcc -lpthread
            功能:使用系统默认的NPTL线程库, 
                     即在默认路径中寻找库文件libpthread.so 
                     默认路径为/usr/lib和/usr/local/lib
      
            当系统默认使用的不是NPTL线程库时(系统较老,2003年以前)
            指定:gcc  -L/usr/lib/nptl   -lpthread
            补充: -L 指定库文件所在的目录
                     -l  指定库文件的名称(-lpthread ,指库文件名为libpthread.so)
      
        总结:一般使用如下形式即可
               gcc   -D_REENTRANT   -lpthread    mythread.c    -o   mythread  
      

      4)实例
      main1.c

      实例
      创建一个线程,并传递一个字符串
      在新线程中,把所传递的字符串打印出来,
      并把字符串转换为大写,再返回给主线程
      新线程结束后,在主线程中,把所返回的结果打印输出。

    #ifdef FUNC_A                            
    
    
    void test_func(void)
    {
        printf("world");
    }  
    
    #else 
    
    void test_func(void)
    {
        printf("hello");
    }
    
    #endif 

    main1.c

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int my_global;
    
    void* my_thread_handle(void *arg) 
    {
        int val;
    
        val = *((int*)arg);
    
        printf("new thread begin, arg=%d
    ", val);
        my_global += val;
    
        sleep(3);
    
        pthread_exit(&my_global);
    
        //  ≤ª‘Ÿ÷¥––
        printf("new thread end
    ");
    }
    
    int main(void)
    {
        pthread_t  mythread;
        int arg;
        int ret;
        void *thread_return;
    
        arg = 100;
        my_global = 1000;
    
        printf("my_global=%d
    ", my_global);
        printf("ready create thread...
    ");
    
        ret = pthread_create(&mythread, 0, my_thread_handle, &arg);
        if (ret != 0) {
            printf("create thread failed!
    ");
            exit(1);
        }
    
        printf("wait thread finished...
    ");
        ret = pthread_join(mythread, &thread_return);
        if (ret != 0) {
            printf("pthread_join failed!
    ");
            exit(1);
        }
        printf("wait thread end, return value is %d
    ", *((int*)thread_return));
        printf("my_global=%d
    ", my_global);
    
        printf("create thread finished!
    ");
    }
    
  • 相关阅读:
    Android之Wifi使用
    Android之浮动小窗口
    Android之Socket的基于UDP传输
    Android之基本常见知识(持续更新)
    Android之打开闪光灯关键代码
    Android之Oauth验证(一)
    Android之WebView简易应用
    Android之短信广播接收内容
    Google HTML/CSS 代码风格指南
    几个 HTML 标签的用法
  • 原文地址:https://www.cnblogs.com/Sico2Sico/p/5384202.html
Copyright © 2011-2022 走看看