zoukankan      html  css  js  c++  java
  • 第八章 多线程编程

    (1) 线程的概念

      相信很多读者参加面试笔试的时候都被问及线程与进程的区别。我做概要分析如下

      1> 进程是线程的载体,一个进程包含一个以上的线程,这些线程运行在进程的地址空间。

      2>  进程是系统资源的分配拥有着,所有进程内的线程均可访问资源。

      3>  线程是处理器调度的基本单位,但进程不是  。

      4>  每一个进程都有一个主线程,其它线程均有主线程直接简介产生。

    (2) 线程的控制  

    #include <pthread.h> 
    int pthread_create(pthread_t *restrict thread,  const pthread_attr_t *restrict attr,  void *(*start_routine)(void*), void *restrict arg);
    
    void pthread_exit(void *value_ptr);   //终止线程本身
    int pthread_join(pthread_t thread, void **value_ptr); //其它线程获取线程的退出码

    pthread_join 获取相关线程推出的返回值。它的值和线程的返回方式有关

    return        一般执行完毕      获取return 返回值一般是数字

    pthread_exit     自己推出   返回退出制定指针的值

    pthread_cancel  其它线程异常终止  返回PTHREAD_CANCELED

    (3)远堆传参

      远堆传参,是指在堆中分配一块内存,又来作为线程启动的参数传递。如果是临时变量的话住线程创建玩子线程可能就会销毁临时变量。因为每个线程有各自的堆栈。所以子线程可能访问不到参数。这也是唯一不遵循内存分配原则的地方(谁分配谁释放)。主线程分配,子线程释放。 当然也可以使用全局变量。

    (4)线程同步

      线程共享同一进程内的资源,为了防止访问冲突,所以需要同步。同步机制。

      1> 互斥锁   同一时刻只能一个线程访问该资源 即锁定 

    #include <pthread.h> 
    int pthread_mutex_destroy(pthread_mutex_t *mutex);   //销毁锁
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//初始化 int pthread_mutex_lock(pthread_mutex_t *mutex); 
    int pthread_mutex_trylock(pthread_mutex_t *mutex); 
    int pthread_mutex_unlock(pthread_mutex_t *mutex);

       用pthread_mutex_init函数初始化的Mutex可以用pthread_mutex_destroy销毁。如果Mutex变量是静态分配的(全局变量或static变量),也可以用宏定义PTHREAD_MUTEX_INITIALIZER来初始化,相

    当于用pthread_mutex_init初始化并且attr参数为NULL。pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

      

      2> 信号量(Semaphore)

         Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1表示有一个可用资源,加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示

    又有了一个可用资源。 信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。  

    #include <semaphore.h> 
     
    int sem_init(sem_t *sem, int pshared, unsigned int value);   //初始化
    int sem_wait(sem_t *sem);                      //等待  获取资源
    int sem_trywait(sem_t *sem);                    //尝试等待   
    int sem_post(sem_t * sem);                                    //释放 资源
    int sem_destroy(sem_t * sem);                                 //销毁

      3> 条件变量  不太常用

    #include <pthread.h> 
     
    int pthread_cond_destroy(pthread_cond_t *cond); 
    int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); //pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    
    int pthread_cond_timedwait(pthread_cond_t *restrictcond, pthread_mutex_t *restrict mutex,  const struct timespec *restrict abstime); 
    
    int pthread_cond_wait(pthread_cond_t *restrict cond,  pthread_mutex_t *restrict mutex); 
    
    int pthread_cond_broadcast(pthread_cond_t *cond); 
    int pthread_cond_signal(pthread_cond_t *cond); 

    一个条件变量总是和一个互斥锁相关。所以使用起来比较繁琐,也不常用。下面是一个生产者和消费者的例子供学习参考。

    #include <stdlib.h> 
    #include <pthread.h> 
    #include <stdio.h> 
     
    struct msg
    { 
       struct msg *next; 
        int num; 
    }; 
     
    struct msg *head; 
    pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; 
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
     
    void *consumer(void *p)
    {
      struct msg *mp; 
     
      for (;;) 
     { 
         pthread_mutex_lock(&lock); 
         while (head == NULL) 
         pthread_cond_wait(&has_product, &lock);   
         mp = head; 
         head = mp->next; 
         pthread_mutex_unlock(&lock); 
         printf("Consume %d
    ", mp->num); 
         free(mp); 
         sleep(rand() % 5); 
     } 
    } 
    void *producer(void *p) 
    { 
         struct msg *mp; 
         for (;;) 
        { 
             mp = malloc(sizeof(struct msg)); 
             mp->num = rand() % 1000 + 1; 
             printf("Produce %d
    ", mp->num); 
             pthread_mutex_lock(&lock); 
             mp->next = head; 
             head = mp; 
             pthread_mutex_unlock(&lock); 
             pthread_cond_signal(&has_product); 
             sleep(rand() % 5); 
         } 
    } 
     
    int main(int argc, char *argv[])  
    { 
         pthread_t pid, cid;   
     
          srand(time(NULL)); 
          pthread_create(&pid, NULL, producer, NULL); 
          pthread_create(&cid, NULL, consumer, NULL); 
          pthread_join(pid, NULL); 
          pthread_join(cid, NULL); 
          return 0; 
    } 

    附加:pthread_detach

      创建一个线程默认的状态是joinable, 如果一个线程运行结束但没有被join,则它的状态类似于进程中的Zombie Process(僵尸进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该调用 pthread_join 来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid)

      但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此

      这时可以在子线程中加入代码    

        pthread_detach(pthread_self ())

      或者父线程调用
        pthread_detach(thread_id)(非阻塞,可立即返回)
      这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。
     
  • 相关阅读:
    STM32驱动TEA5767收音机模块
    stm32驱动DS1302芯片
    NRF24L01无线通讯模块驱动
    MQ-2烟雾传感器启动
    HCSR04超声波传感器驱动
    RDA5820收音机芯片驱动
    SD卡初始化以及命令详解
    STM32硬件IIC操作
    STM32驱动MPU6050
    BMP085气压传感器驱动
  • 原文地址:https://www.cnblogs.com/wolfrickwang/p/3186442.html
Copyright © 2011-2022 走看看