zoukankan      html  css  js  c++  java
  • linux C总结篇(线程)上

    (百度百科来凑数的,哈哈~~~) 线程:有时被称为轻量级进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

    线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

    创建线程:

    创建线程函数:

       #include <pthread.h>
       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
    

    参数说明:1. thread:pthread_t类型的指针 ,用来返回所创建的线程的ID (非负数)

    2.attr :指定线程的属性。默认为NULL 。稍后介绍

    3.start_routine:线程创建后所要调用的函数,这是一个函数指针。

    插曲( 指针函数与函数指针的简单区别):
    指针函数:int *f(int a, int b);
    函数指针:int (*f)(int a, int b);

    说明: 函数指针就是用括号把你的函数名括起来,加一个*号。指针函数就是加一个*号

    4.arg:传递给线程函数的参数 。

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    typedef struct {
        int a;
        int b;
    }TT ;
    void *creat_pthread(void *arg)
    {
        TT *p = (TT *)arg;
        pthread_t newthid ;
        int i;
        newthid=pthread_self() ;
        printf("the new  pthread ID is %u 
    ",newthid) ;
        for(i= 0 ;i< (p->a)  ; i++ )
           printf("---------------------------%d
    ",i );
        return NULL ;
    }
    int main(void)
    {
        TT *p = (TT *)malloc(sizeof(TT)) ;//注意开辟空间,我就被坑在这里了@~@
        pthread_t thid ; 
        int n  ,i;
        p->a= 100 ;
        p->b= 30 ; 
        printf("%d %d
    ",p->a,p->b);
        printf("the main  pthread ID is %u 
    ",pthread_self()) ;
        if(pthread_create(&thid ,NULL ,creat_pthread ,(void *)p) != 0)
        {
            printf("creat pthread is failed !! 
    ");
            exit(-1);
        }
        for(i= 0;i<  100;i++)
            printf("+++++++++++++++++++++++%d
    ",i);
        sleep(5);
        exit(0);
    }
    

    执行结果:

    这里写图片描述

    注意事项:

    1.如果调用函数返回一个void 指针,则不需要强转。

    2. 参数arg ,必须强转为void * 的类型,然后再在调用函数中转回来即可

    3.传递多个参数时,必须申明一个结构体来包含所有的参数,然后再传入线程函数其实也是一个封装的思想了

    4.结果也说明,线程执行顺序是不确定的,是由CPU 的调度算法(时间片的分配)所决定的 。

    一些简单函数的说明:

      pthread_t pthread_self(void);//取得本线程ID 
      int pthread_equal(pthread_t t1, pthread_t t2);//判断两个线程ID 是否指向同一个线程
     int pthread_once(pthread_once_t *once_control,void (*init_routine)(void)); //保证init_routine 线程函数在进程中只执行一次
    

    线程属性 :

    该结构体是

     typedef struct
     {
     int   detachstate;     线程的分离状态
     int    schedpolicy;   线程调度策略
    struct sched_param    schedparam;   线程的调度参数
     int        inheritsched;    线程的继承性
     int        scope;          线程的作用域
     size_t     guardsize; 线程栈末尾的警戒缓冲区大小
     int        stackaddr_set;
     void *     stackaddr;      线程栈的位置
     size_t     stacksize;       线程栈的大小
     }pthread_attr_t;
    

    参数说明:

    schedpolicy:线程调度策略,只要有三种:(1)正常非实时。(2):实时,轮转。(3):实时,先入先出。(后两种调度只对root 用户有效)

    schedparam :一个struct sched_param 结构体,其中有一个sched_priority 表示线程优先级,只有当调度策略为实时才有效,缺省为0

    scope:线程优先级有效范围

    线程终止(两种):

    1.return 返回

    2. 使用pthread_exit()函数:

      #include <pthread.h>
     void pthread_exit(void *retval);
    

    两种特殊情况:

    1.在主线程中线程过早返回或者是调用exit 函数,则整个进程都会终止。就会导致所有的线程终止 。

    2.在主线程中线程调用pthread_exit函数退出,进程不会结束,直到所有线程结束,进程才会结束

    资源释放:

    有些资源必须在一段时间内被一个线程所持有,其他线程使用资源时提出申请,也就是我所说的厕所的问题。现在我们假设一种情况,如果一个线程在终止时并没有释放资源,那么其他线程也无法使用,这就会导致死锁!!那么linux 该如何解决这个问题呐???

    linux 系统提供了一对函数用于主动释放资源

       #include <pthread.h>
    
       1.void pthread_cleanup_push(void (*routine)(void *),
                                 void *arg);
       2.void pthread_cleanup_pop(int execute);
    

    说明:1.这两个函数的调用之间的程序段中的终止动作都会执行pthread_cleanup_push所指定的清除函数。

    2.pthread_cleanup_push带有一个{ ,pthread_cleanup_pop带有一个},因此这两个函数必须成对出现,且必须位于程序的同一段代码中才能编译通过。

    线程间的同步(相当于进程中的wait 函数)

       #include <pthread.h>
    
       int pthread_join(pthread_t thread, void **retval);
    

    说明:1.pthread_join用来等待一个线程的结束,调用pthread_join的线程被挂起,回收所等待线程的资源。

    2.一个线程只允许一个线程使用pthread_join来等待

    3.被等待的线程应该处于”join”的状态,而非死亡状态(DETACHED)

    4.为避免内存泄漏,因此所有的线程终止时,必须处于两种情况之中(1.死亡状态(DETACHED)2.使用pthread_join和回收资源)

    小示例:

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    int *creat_pthread(int *n  )
    {
        pthread_t newthid ;
        int i;
        newthid=pthread_self() ;
        printf("the new  pthread ID is %d 
    ",newthid) ;
        for(i= 0 ;i< *n ;i++)
           printf("------------------------%d
    ",i );
        pthread_exit((void *)-100);
    }
    int main(void)
    {
        pthread_t thid ; 
        int n  ,i;
        int status ;
        printf("main pthread ID is %d 
    ",pthread_self());
        printf("please input  the   n :  ");
        scanf("%d",&n);
        if(pthread_create(&thid ,NULL ,(void *)creat_pthread ,&n) != 0)
        {
            printf("creat pthread is failed !! 
    ");
            exit(-1);
        }
        pthread_join(thid,(void *)&status);
        printf("the new pthread's exit number is %d 
    ",status);
        exit(0);
    }
    

    执行结果:

    这里写图片描述

    说明:1.status 存放新开的线程的退出码(-100)

    2.pthread_join 阻塞主线程,等待新开的线程结束。(类似于函数的调用)

    感觉后面的要介绍的内容过于多了一点,因此分成两个部分来叙述。望谅解!!!

  • 相关阅读:
    C语言常用函数-findfirst()搜索指定磁盘目录里文件函数
    C语言常用函数-getcwd()获取当前工作目录函数
    C语言常用函数目录
    C语言常用函数-_rmdir()建立目录函数
    C语言常用函数-mkdir()建立目录函数
    NX二次开发-UF_DRF_ask_dim_info获得图纸尺寸属于哪个视图和图纸页
    NX二次开发-NXOpenC++属性操作
    VMware虚拟机设置双网卡上网
    FreeCAD二次开发-计算模型是否报错,报错则停止
    NX二次开发-自动将NX标题设置为prt路径
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335339.html
Copyright © 2011-2022 走看看