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,则该线程运行结束后会自动释放所有资源。
     
  • 相关阅读:
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    how to use automapper in c#, from cf~
  • 原文地址:https://www.cnblogs.com/wolfrickwang/p/3186442.html
Copyright © 2011-2022 走看看