linux线程

现代操作系统特定引入“进程”的概念。

    1. 进程地址空间是独立的,

        创建一个进程的系统开销比较大,要拷贝整个地址空间,
        进程切换开销比较大;

    2. 进程间的数据是独立的,分开的,如果进程间需要进行

        数据交换,则需要用到进程间通信(IPC)
        进程通信开销比较大。

于是,就有人提出能不能在同一个进程内实现“任务(程序,代码)”的
    并发执行呢?


线程概念

    1. 线程是比进程更小的活动单位,它是进程中的一个执行路径(执行分支)
    
    2. 线程同进程内其他线程共享进程地址空间;
    
    
    =>

线程特点:

    1. 创建一个线程比创建一个进程开销小得多
            在进程内部创建一个线程,不需要拷贝进程的地址空间,
            新线程和其他的线程共享进程的地址空间。
            而进程与进程间地址空间是独立的,创建时需要拷贝整个进程地址空间。
            
    2. 实现线程间通信十分方便,因为一个进程创建的多个线程直接共享整个进程的
        内存区域。
        
    3. 线程也是一个动态概念。
    
    4. 进程是操作系统资源分配的最小单位,线程是调度的最小单位。
    
    5. 在进程内创建多线程,可以提高系统的并行处理能力,加快进程的处理速度。
    
    6. 每个进程会自动有一个主线程,就是main函数, 这个主线程如果执行完了
        那么进程就结束了。

        
    “并发粒度不一样”
    

POSIX线程实现接口:(POSIX--Portable Operation System Interface)

    POSIX实现了线程,我们叫POSIX thread, pthread
    linux中pthread的接口函数:

     sudo apt-get install manpages-posix-dev 用于安装pthread相关的manual手册(因为man中查不到pthread_mutex_init,pthread_mutex_destory等函数)


1.创建一个线程

2.线程退出

3.线程资源回收

4. 线程间同步机制
    (1) 互斥
    (2) 条件变量


1.创建一个线程

    pthread_create
    NAME
       pthread_create - create a new thread

    线程用来并发执行一个任务,"任务"就是代码,
    在C语言,代码(指令)是以函数形式组织。

    在pthread中,每个线程都有一个唯一的ID,用类型pthread_t来表示。
    而且我们可以通过函数:pthread_t pthread_self(void);来获取自身线程的ID
    
    而且每个线程都有自己的属性,用类型pthread_attr_t来表示

SYNOPSIS
       #include <pthread.h>

       int pthread_create(pthread_t *thread,
                   const pthread_attr_t *attr,                    
                   void *(*start_routine) (void *),
                   void *arg);

            thread: 指向pthread_t,用来保存新创建的线程的ID的
            attr:指向线程属性结构体pthread_attr_t, 一般为NULL,
                表示采用默认的属性。
            start_routine: 函数指针。指向的函数的类型为返回一个
                    void*,带一个void*参数,start_routine指向的函数,就是
                    线程函数,新创建的线程要执行的任务。
            arg: 该参数,将作为线程函数的实际参数传给线程函数

        返回值:
            成功返回0,
            失败返回-1, errno被设置。
                   

       Compile and link with -pthread.编译时需要指定,如:gcc main.c -o main -l pthread



2.线程退出

    三种方式可以使线程结束:
        (1) 线程函数返回,任务完成。
        (2)在线程函数中调用pthread_exit()
        (3) It is cancelled (别的线程调用pthread_cancell,让线程"取消了")
    
    2.2 pthread_exit
    NAME
       pthread_exit - terminate calling thread

SYNOPSIS
       #include <pthread.h>
           
        pthread_exit用来结束调用线程,
       void pthread_exit(void *retval);
           retval:返回一个指针。

       Compile and link with -pthread.


    2.3  

    NAME
       pthread_cancel - send a cancellation request to a thread

SYNOPSIS
       #include <pthread.h>

        pthread_cancel用来发送一个"取消"请求给thread指定的线程,
        但是接收到"取消"请求的线程,不一定会成功取消并退出
        这得取决于,接收线程的属性(cancel state)

        我们可以调用pthread_setcancelstate来 enable/disable线程这个属性(
        可"取消"属性,cancel state)

        
       int pthread_cancel(pthread_t thread)


    SYNOPSIS
       #include <pthread.h>

       int pthread_setcancelstate(int state, int *oldstate);
               state: 要设置的取消状态
                       PTHREAD_CANCEL_ENABLE  :可被别人取消
                       PTHREAD_CANCEL_DISABLE: 不可被别人取消
               oldstate:保存上次的状态值
           返回值:
               成功返回0,
               失败返回-1, errno被设置



3.线程资源回收

    pthread_join等待一个指定的线程退出,该函数会阻塞调用线程,
    直到被等待的线程退出,它有两个作用:
        (1) 等待线程退出;
        (2) 回收被等待线程的资源的

    线程退出了,不代表其资源释放完全了,(这个时候需要调用
    pthread_join去回收其资源),
    线程退出了是否代表其资料完全释放,这个得取决于一个
    线程属性: detach state(分离属性)
                PTHREAD_CREATE_DETACHED  -> detach state : 分离状态,线程结束,资源就自动释放
                PTHREAD_CREATE_JOINABLE   -> joinable state : joinable state , 这种状态,就必须要另外线程调用
                                                pthread_join来回收其资源。
        我们可以调用pthread提供的API来设置线程的detach state:
            NAME
               pthread_detach - detach a thread

        SYNOPSIS
               #include <pthread.h>

               int pthread_detach(pthread_t thread);

               Compile and link with -pthread.

        DESCRIPTION
            pthread_detach这个函数标记thread代表的那个线程
            为分离状态。
        
            当一个处于分离状态的线程退出时,它的资源
            会自动回收给系统,没有必要让另外的线程手动
            回收它的资源。

            试图去分离一个已经处于分离状态的线程将导致不确定
            的情况。


        
    NAME
       pthread_join - join with a terminated thread

    SYNOPSIS
       #include <pthread.h>

       int pthread_join(pthread_t thread, void **retval);
        thread:要等待哪个线程退出
        retval:二级指针,用来保存退出线程的返回值的。
                此处为什么一定要用二级指针呢? 因为一个线程的返回值是void*类型
        返回值:
            成功返回0,
            失败返回-1,  errno被设置
        
        
    

4. 线程间同步机制

    (1) 互斥

            多个线程同时访问一个共享资源时,我们必须要
            "避免竞争"
            a. 信号量机制
                    SYSTEM  V 信号量
                    POSIX信号量(有名/无名)
            b. 线程互斥锁(pthread mutex)
                线程互斥锁专门用来实现在线程间互斥用的,
                它的原理和功能,作用等都和信号量一样。
                pthread_mutex_t这种类型就是用来表示线程互斥锁的。

                pthread mutex的操作:

                (1) 初始化一个互斥锁; 销毁一个互斥锁


                    pthread_mutex_init用特定的线程互斥锁属性(pthread_mutexattr_t)
                    来初始化mutex
                         int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                                         const pthread_mutexattr_t *restrict attr);
                                     mutex:指向要初始化的线程互斥锁
                                     attr:指向线程互斥锁的属性,一般为NULL,
                                         表示采用默认属性。
                                 返回值:
                                     成功返回0
                                     失败返回-1, errno被设置

                    pthread_mutex_destroy用来销毁mutex指向的线程互斥锁
                    int pthread_mutex_destroy(pthread_mutex_t *mutex);
     

                (2) lock; //P操作
                        pthread_mutex_lock用来对互斥锁进行P操作的
                        会阻塞到获取该互斥锁,或出错。
                        返回0表示,获取了互换锁
                        返回-1 表示出错了,errno被设置
                       int pthread_mutex_lock(pthread_mutex_t *mutex);  //block


                           pthread_mutex_trylock用来对互斥锁进行P操作,只不过
                           它是非阻塞的版本,能获取则获取,不能获取就返回。

                           返回0表示,获取了互斥锁
                           返回-1表示没获取到,(可能是出错了,errno)
                          int pthread_mutex_trylock(pthread_mutex_t *mutex);
      



                (3) unlock; //V操作

                    线程互斥锁的V操作
                 int pthread_mutex_unlock(pthread_mutex_t *mutex);
                
    

    (2) 条件变量

        (2.1)初始化/销毁一个条件变量

            
                pthread_cond_init用来初始化cond指向条件变量
               int pthread_cond_init(pthread_cond_t * cond,
                                      const pthread_condattr_t * attr);
                          cond: 指向要初始化的条件变量
                          attr:指向条件变量的属性,一般为NULL,表示采用默认属性
                      返回值:
                          成功返回0
                          失败返回-1, errno被设置


        
                pthread_cond_destroy用来销毁cond指向的条件变量
               int pthread_cond_destroy(pthread_cond_t *cond);
           

        (2.2)等待一个条件变量

            条件变量本身就是一个共享对象(多个线程都可以访问它),
            它本身也需要保护。MC(Mutex  Condition)


                    //死等,直到被唤醒(返回0, 表示条件产生,
                    返回-1,表示失败了)
                 int  pthread_cond_wait(pthread_cond_t *restrict cond,
                          pthread_mutex_t *restrict mutex);



                    //有限等待。
                    //返回0表示条件产生,
                    //返回-1 表示失败,errno
                   int pthread_cond_timedwait(pthread_cond_t *restrict cond,
                          pthread_mutex_t *restrict mutex,
                          const struct timespec *restrict abstime);

                               struct timespec {
                                   time_t tv_sec;      // Seconds
                                   long   tv_nsec;     // Nanoseconds [0 .. 999999999]
                               };


                          例子:
                              struct timespce ts;  
                              clock_getime(CLOCK_REALTIME, &ts);
                              //ts.tv_sec +=5;
                              //ts.tv_nsec
                              ts.tv_nsec += 1000000;
                              if (ts.tv_nsec >=1000000000L)
                        {
                            ts.tv_sec++;
                            ts.tv_nsec -= 1000000000L;
                        }


              
            NOTE:调用上述函数时,需要把锁住的互斥锁传入,上述等待函数
            在让线程休眠(让出CPU)前,会释放该互斥锁,然后阻塞,直到被
            唤醒,再次锁住该互斥锁,并从等待函数中返回。
                  

            (2.3)唤醒一个条件变量


    
               int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒条件变量上等待的所有线程
            int pthread_cond_signal(pthread_cond_t *cond);  //唤醒条件变量上等待的一个线程



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值