• Linux线程02


    学习内容

    线程的取消
    线程和信号,与多进程的信号有不同
    线程安全,一切麻烦从共享资源开始
    线程同步,各种锁的使用

    线程取消

    int pthread_cancel(pthread_t thread);

    线程取消
    线程取消点

    // 本程序演示线程的取消。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    
    int var=0;
    
    void *thmain(void *arg);    // 线程主函数。
    
    int main(int argc,char *argv[])
    {
      pthread_t thid;
    
      // 创建线程。
      if (pthread_create(&thid,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    
      usleep(100); pthread_cancel(thid);
    
      int result=0;
      void *ret;
      printf("join...\n");
      result=pthread_join(thid,&ret);   printf("thid result=%d,ret=%ld\n",result,ret);
      printf("join ok.\n");
    
      printf("var=%d\n",var);
    }
    
    void *thmain(void *arg)    // 线程主函数。
    {
      // pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    
      for (var=0;var<400000000;var++)
      {
        ;
        pthread_testcancel();
      }
      return (void *) 1;
    }
    
    

    线程和信号

    进程和信号 and 线程和信号的区别:
    线程和信号
    线程和信号2

    线程安全

    什么是可重入函数?
    可重入的函数简单来说就是可以被中断的函数
    一文理解可重入函数

    什么是原子性?

    什么是可见性?
    可见性
    什么是顺序性?
    顺序性
    volatile关键字?

    volatile不是原子的。

    如何解决线程安全?

    解决线程安全

    原子操作只支持整数。支持对象要用线程同步

    线程同步,各种锁的使用

    互斥锁
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    

    互斥锁的demo:

    #include <pthread.h>
    
    
    pthread_mutex_t mutex;
    int max = 0;
    void* arg_main1(void* arg) {
        for(int i = 0;i < 100; i++) {
            pthread_mutex_init(&mutex,NULL);
            max += 1;
            printf("arg_main1 max = %d \n",max);
            //sleep(1);
            pthread_mutex_unlock(&mutex);
        } 
    }
    void* arg_main2(void* arg) {
        
        for(int i = 0;i < 100; i++) {
            pthread_mutex_init(&mutex,NULL);
            max += 1;
            printf("arg_main2 max = %d \n",max);
            //sleep(1);
            pthread_mutex_unlock(&mutex);
        } 
    }
    
    int main()
    {
        
        pthread_mutex_init(&mutex,NULL);
    
        pthread_t pid1,pid2;
        pthread_create(&pid1,NULL,&arg_main1,NULL);
        pthread_create(&pid2,NULL,&arg_main2,NULL);
    
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        printf("max = %d \n",max);
    
        pthread_mutex_destroy(&mutex);
        return 0;
    }
    
    锁的属性

    锁的属性
    锁的属性
    锁的属性

    互斥锁和自旋锁的区别?

    互斥锁不消耗cpu,线程会休眠,而自旋锁会消耗cpu,它用cpu使用
    使用自旋锁假设等待时间很短。
    等待时间短使用自旋锁,等待时间长使用互斥锁。
    pthread_mutex_init和pthread_spin_init 第二个参数不同,mutex是属性,spin是一个标志。
    加锁解锁时候也不同:一个要两个参数,一个要一个参数。

    自旋锁

    api如下:

    int pthread_spin_destroy(pthread_spinlock_t *lock);
    int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
    PTHREAD_PROCESS_PRIVATE 能否共享自旋锁? 一般填私有的。
    int pthread_spin_lock(pthread_spinlock_t *lock);
    int pthread_spin_trylock(pthread_spinlock_t *lock);
    
    

    自旋锁使用demo:

    #include <pthread.h>
    
    pthread_spinlock_t mutex;// 定义自旋锁
    
    int max = 0;
    void* arg_main1(void* arg) {
        for(int i = 0;i < 100; i++) {
            pthread_spin_lock(&mutex);
            max += 1;
            printf("arg_main1 max = %d \n",max);
            usleep(1);
            pthread_spin_unlock(&mutex);
        } 
    }
    void* arg_main2(void* arg) {
        
        for(int i = 0;i < 100; i++) {
            pthread_spin_lock(&mutex);
            max += 1;
            printf("arg_main2 max = %d \n",max);
            usleep(2);
            pthread_spin_unlock(&mutex);
        } 
    }
    
    int main()
    {
        
        pthread_spin_init(&mutex,PTHREAD_PROCESS_PRIVATE);
    
        pthread_t pid1,pid2;
        pthread_create(&pid1,NULL,&arg_main1,NULL);
        pthread_create(&pid2,NULL,&arg_main2,NULL);
    
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        printf("max = %d \n",max);
    
        pthread_spin_destroy(&mutex);
        return 0;
    }
    
    
    读写锁

    api:

    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock);// 读锁
    int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock);// 写锁
    int pthread_rwlock_unlock(pthread_rwlock_t *__rwlock);// 解锁
    
    1. 读写锁支持高并发
    2. 读写锁有三种状态:读模式加锁,写模式加锁和不加锁。
      读写锁
    读写锁的特点

    读写锁的特点

    读写锁注意点

    读写锁注意点

    读写锁和互斥锁的区别?
    1. 读写锁有三种状态。互斥锁只有两种。
      读写锁demo:
    // 本程序演示线程同步-读写锁。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <signal.h>
    
    pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER;   // 声明读写锁并初始化。
    
    void *thmain(void *arg);    // 线程主函数。
    
    void handle(int sig);       // 信号15的处理函数。
    
    int main(int argc,char *argv[])
    {
      signal(15,handle);       // 设置信号15的处理函数。
    
      pthread_t thid1,thid2,thid3;
    
      // 创建线程。
      if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    sleep(1);
      if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    sleep(1);
      if (pthread_create(&thid3,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    
      // 等待子线程退出。
      pthread_join(thid1,NULL);  pthread_join(thid2,NULL);  pthread_join(thid3,NULL);  
    
      pthread_rwlock_destroy(&rwlock);  // 销毁锁。
    }
    
    void *thmain(void *arg)    // 线程主函数。
    {
      for (int ii=0;ii<100;ii++)
      {
        printf("线程%lu开始申请读锁...\n",pthread_self());
        pthread_rwlock_rdlock(&rwlock);    // 加锁。
        printf("线程%lu开始申请读锁成功。\n\n",pthread_self());
        sleep(5);
        pthread_rwlock_unlock(&rwlock);    // 解锁。
        printf("线程%lu已释放读锁。\n\n",pthread_self());
    
        if (ii==3) sleep(8);
      }
    }
    
    void handle(int sig)       // 信号15的处理函数。
    {
      printf("开始申请写锁...\n");
      pthread_rwlock_wrlock(&rwlock);    // 加锁。
      printf("申请写锁成功。\n\n");
      sleep(10);
      pthread_rwlock_unlock(&rwlock);    // 解锁。
      printf("写锁已释放。\n\n");
    }
    
    
    条件变量
    1. 条件变量和互斥锁一起使用。实现生产者消费者模型,还可以通知功能。
      条件变量

    api:

    pthread_cond_t cond;// 定义条件变量
    int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex)
    int pthread_cond_signal(pthread_cond_t *__cond)
    int pthread_cond_destroy(pthread_cond_t *__cond)
    

    demo:

    pthread_cond_t cond;// 定义条件变量
    pthread_mutex_t mutex;
    int max = 0;
    void* arg_main1(void* arg) {
        while(1) {
                printf("线程%lu开始等待条件信号...\n",pthread_self());
                pthread_cond_wait(&cond,&mutex);    // 等待条件信号。
                printf("线程%lu等待条件信号成功。\n\n",pthread_self());
        }
    }
    void func(int sig) {
        printf("发送条件信号...\n");
         pthread_cond_signal(&cond);
    }
    
    int main()
    {
        signal(15,func);
    
        pthread_cond_init(&cond,NULL);
        pthread_mutex_init(&mutex,NULL);
    
        pthread_t pid1,pid2;
        pthread_create(&pid1,NULL,&arg_main1,NULL);
        pthread_create(&pid2,NULL,&arg_main1,NULL);
    
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        
    
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mutex);
        return 0;
    }
    
    信号量

    线程的信号量不能用在进程中。

    api



    // 本程序演示线程同步-信号量。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    int var;
    
    sem_t sem;      // 声明信号量。
    
    void *thmain(void *arg);    // 线程主函数。
    
    int main(int argc,char *argv[])
    {
      sem_init(&sem,0,1);   // 初始化信号量。
    
      pthread_t thid1,thid2;
    
      // 创建线程。
      if (pthread_create(&thid1,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
      if (pthread_create(&thid2,NULL,thmain,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    
      // 等待子线程退出。
      printf("join...\n");
      pthread_join(thid1,NULL);  
      pthread_join(thid2,NULL);  
      printf("join ok.\n");
    
      printf("var=%d\n",var);
    
      sem_destroy(&sem);  // 销毁信号量。
    }
    
    void *thmain(void *arg)    // 线程主函数。
    {
      for (int ii=0;ii<1000000;ii++)
      {
        sem_wait(&sem);    // 加锁。
        var++;
        sem_post(&sem);  // 解锁。
      }
    }
    
    

    互斥锁的细节

    互斥锁的细节

  • 相关阅读:
    (转) 建立自己的MemberShip数据库
    '??' 语法
    c# 静态构造函数(转)
    ReSharp+VAssistX+VS2003 的个人设置
    支持多种数据类型的ListView排序
    学习笔记
    Java实验报告(实验二)
    Java实验报告(实验一)
    java数组中null和空的区别。
    网页选项卡功能
  • 原文地址:https://www.cnblogs.com/yaozhenhua/p/16183307.html
Copyright © 2020-2023  润新知