zoukankan      html  css  js  c++  java
  • 【Linux 线程】线程同步《一》

    1、线程同步概念

    线程同步:在多个线程访问共享数据时,有先后次序。

    在一般情况下,创建一个线程是不能提高程序的执行效率的,所以要创建多个线程。但是多个线程同时运行的时候可能调用线程函数,在多个线程同时对同一个内存地址进行写入,由于CPU时间调度上的问题,写入数据会被多次的覆盖,所以就要使线程同步。
    线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,目前实现线程同步的方法有很多,临界区对象就是其中一种。
    常见的多线程同步的方式:临界区、互斥量、事件、信号量。
    临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别如下:
    1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
    2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
    3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
    4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作。
     

    2、互斥锁

    posix下抽象了一个锁类型的结构:ptread_mutex_t。通过对该结构的操作,来判断资源是否可以访问。顾名思义,加锁(lock)后,别人就无法打开,只有当锁没有关闭(unlock)的时候才能访问资源。

    主要有如下5个函数:

    1)pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex attr_t *attr);
    // 初始化锁变量mutex。
    // attr为锁属性(自己的值只能被自己的指针改变),NULL值为默认属性。
    2)pthread_mutex_lock(pthread_mutex_t *mutex);
    // 加锁(阻塞操作)
    3)pthread_mutex_trylock(pthread_mutex_t *mutex);
    // 试图加锁(不阻塞操作)
    // 当互斥锁空闲时将占有该锁;否则立即返回
    // 但是与2不一样的是当锁已经在使用的时候,返回为EBUSY,而不是挂起等待。
    4)pthread_mutex_unlock(pthread_mutex_t *mutex);
    // 释放锁
    
    (5)pthread_mutex_destroy(pthread_mutex_t *mutex);
    // 使用完后删除

    举例1:

      1 /*************************************************************************
      2     > File Name: pthread_mutex1.c
      3     > Summary: 互斥锁举例1
      4     > Author: xuelisheng 
      5     > Created Time: 2018年12月17日
      6  ************************************************************************/
      7 /*
      8 #include <stdio.h>
      9 #include <stdlib.h>  
     10 #include <unistd.h>  
     11 #include <pthread.h>  
     12 typedef struct ct_sum  
     13 {   
     14     int sum;  
     15     pthread_mutex_t lock;  
     16 }ct_sum;  
     17 
     18 void * add1(void * cnt)  
     19 {       
     20     // 加互斥锁
     21     pthread_mutex_lock(&(((ct_sum*)cnt)->lock));  
     22     int i;  
     23     for(i=0; i<50; i++)
     24     {  
     25         (*(ct_sum*)cnt).sum+=i;
     26     } 
     27     printf("thread 1 printf sum = %d
    ", ((ct_sum *)cnt)->sum);
     28     pthread_mutex_unlock(&(((ct_sum*)cnt)->lock));  
     29     pthread_exit(NULL);  
     30     return 0;  
     31 }  
     32 
     33 void * add2(void *cnt)  
     34 {       
     35     int i;  
     36     cnt= (ct_sum*)cnt;  
     37     pthread_mutex_lock(&(((ct_sum*)cnt)->lock));  
     38     for(i=50; i<101; i++)  
     39     {    
     40         (*(ct_sum*)cnt).sum+=i;         
     41     }  
     42     printf("thread 2 printf sum = %d
    ", ((ct_sum *)cnt)->sum);
     43     pthread_mutex_unlock(&(((ct_sum*)cnt)->lock));  
     44     pthread_exit(NULL);  
     45     return 0;  
     46 }  
     47 
     48 int main(void)  
     49 {   
     50     int i;  
     51     pthread_t ptid1, ptid2;  
     52     int sum = 0;  
     53     ct_sum cnt;  
     54     //初始化互斥锁
     55     pthread_mutex_init(&(cnt.lock),NULL);  
     56     cnt.sum=0;  
     57     // 创建线程1
     58     pthread_create(&ptid1,NULL,add1,&cnt);  
     59     // 创建线程2
     60     pthread_create(&ptid2,NULL,add2,&cnt);  
     61 
     62     pthread_mutex_lock(&(cnt.lock));  
     63     printf("sum %d
    ",cnt.sum);  
     64     pthread_mutex_unlock(&(cnt.lock));  
     65     pthread_join(ptid1,NULL);  
     66     pthread_join(ptid2,NULL);  
     67     pthread_mutex_destroy(&(cnt.lock));  
     68     return 0;  
     69 }
     70 */
     71 
     72 /*
     73 关于pthread_exit和pthread_join的联合使用
     74 一般都是pthread_exit在线程内退出,然后返回一个值。这个时候就跳到主线程的pthread_join了(因为一直在等你结束),这个返回值会直接送到pthread_join,实现了主与分线程的通信。
     75 */
     76 #include <stdio.h>
     77 #include <stdlib.h>  
     78 #include <unistd.h>  
     79 #include <pthread.h>  
     80 typedef struct ct_sum1 
     81 {   
     82     int sum;  
     83     pthread_mutex_t lock;  
     84 };  
     85 
     86 struct ct_sum1 ct_sum;
     87 
     88 void * add1()  
     89 {       
     90     // 加互斥锁
     91     pthread_mutex_lock(&ct_sum.lock);  
     92     int i;  
     93     for(i=0; i<50; i++)
     94     {  
     95         ct_sum.sum+=i;
     96     } 
     97     printf("thread 1 printf sum = %d
    ", ct_sum.sum);
     98     // 解锁
     99     pthread_mutex_unlock(&ct_sum.lock);  
    100     // pthread_exit用于强制退出一个线程(非执行完毕退出),一般用于线程内部。
    101     pthread_exit(NULL);  
    102     return 0;  
    103 }  
    104 
    105 void * add2()  
    106 {       
    107     int i;   
    108      // 加互斥锁
    109     pthread_mutex_lock(&ct_sum.lock);  
    110     for(i=50; i<101; i++)  
    111     {    
    112         ct_sum.sum+=i;         
    113     }  
    114     printf("thread 2 printf sum = %d
    ", ct_sum.sum);
    115     // 解锁
    116     pthread_mutex_unlock(&ct_sum.lock);  
    117     // pthread_exit用于强制退出一个线程(非执行完毕退出),一般用于线程内部。
    118     pthread_exit(NULL);  
    119     return 0;  
    120 }  
    121 
    122 int main(void)  
    123 {   
    124     ct_sum.sum = 0;
    125     pthread_t ptid1, ptid2;  
    126     int sum = 0;  
    127     //初始化互斥锁
    128     pthread_mutex_init(&(ct_sum.lock),NULL);  
    129     // 创建线程1
    130     pthread_create(&ptid1,NULL,add1,NULL);  
    131     // 创建线程2
    132     pthread_create(&ptid2,NULL,add2,NULL);  
    133     // 阻塞主线程,回收子线程
    134     pthread_join(ptid1,NULL);  
    135     pthread_join(ptid2,NULL);  
    136      
    137     printf("sum %d
    ",ct_sum.sum);  
    138     // 销毁互斥锁
    139     pthread_mutex_destroy(&(ct_sum.lock));  
    140     return 0;  
    141 }

    运行结果:

    thread 1 printf sum = 1225
    thread 2 printf sum = 5050
    sum 5050

    举例2:

     1 /*************************************************************************
     2     > File Name: pthread_mutex2.c
     3     > Summary: 互斥锁举例2(多线程写文件---没有加锁的情形)
     4     > Author: xuelisheng 
     5     > Created Time: 2018年12月17日
     6  ************************************************************************/
     7 #include <stdio.h> 
     8 #include <pthread.h> 
     9 #include <malloc.h> 
    10 
    11 const char filename[] = "hello"; 
    12 void* thread(void *id)
    13 { 
    14     int num = *(int *)id; // 写文件的操作 
    15     FILE *fp = fopen(filename, "a+"); 
    16     int start = *((int *)id); 
    17     int end = start + 1; 
    18     setbuf(fp, NULL);// 设置缓冲区的大小 
    19     fprintf(stdout, "%d
    ", start); 
    20     for (int i = (start * 10); i < (end * 10); i ++)
    21     { 
    22         // 写文件
    23         fprintf(fp, "%d	", i); 
    24     } 
    25     fprintf(fp, "
    "); 
    26     fclose(fp); 
    27     return NULL; 
    28 }
    29 
    30 int main()
    31 { 
    32     // 设置线程个数
    33     int num_thread = 5;
    34     // 堆上申请指向每个线程的指针 
    35     pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread); 
    36     int * id = (int *)malloc(sizeof(int) * num_thread); 
    37     for (int i = 0; i < num_thread; i++)
    38     { 
    39         id[i] = i; 
    40         if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0)
    41         { 
    42             printf("thread create failed!
    "); 
    43             return 1; 
    44         } 
    45     } 
    46     for (int i = 0; i < num_thread; i++)
    47     { 
    48         pthread_join(pt[i], NULL); 
    49     } // 释放资源 
    50     free(pt); 
    51     free(id); 
    52     return 0; 
    53 }

    运行结果:

    屏幕输出:

    1
    0
    2
    3
    4

    输出文件(hello):

    举例3(更改举例2出现的问题):

     1 /*************************************************************************
     2     > File Name: pthread_mutex3.c
     3     > Summary: 互斥锁举例3(多线程写文件---加锁的情形)
     4     > Author: xuelisheng 
     5     > Created Time: 2018年12月17日
     6  ************************************************************************/
     7 #include <stdio.h> 
     8 #include <pthread.h> 
     9 #include <malloc.h> 
    10 
    11 pthread_mutex_t mutex;
    12 const char filename[] = "hello"; 
    13 void* thread(void *id)
    14 { 
    15     int num = *(int *)id; // 写文件的操作
    16     // 加锁
    17     if (pthread_mutex_lock(&mutex) != 0){
    18                 fprintf(stdout, "lock error!
    ");
    19     } 
    20     FILE *fp = fopen(filename, "a+"); 
    21     int start = *((int *)id); 
    22     int end = start + 1; 
    23     setbuf(fp, NULL);// 设置缓冲区的大小 
    24     fprintf(stdout, "%d
    ", start); 
    25     for (int i = (start * 10); i < (end * 10); i ++)
    26     { 
    27         // 写文件
    28         fprintf(fp, "%d	", i); 
    29     } 
    30     fprintf(fp, "
    "); 
    31     fclose(fp); 
    32     // 解锁
    33     pthread_mutex_unlock(&mutex);
    34     return NULL; 
    35 }
    36 
    37 int main()
    38 { 
    39     // 设置线程个数
    40     int num_thread = 5;
    41     // 堆上申请指向每个线程的指针 
    42     pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread); 
    43     int * id = (int *)malloc(sizeof(int) * num_thread); 
    44     // 初始化互斥锁 
    45     if (pthread_mutex_init(&mutex, NULL) != 0)
    46     { 
    47         // 互斥锁初始化失败 
    48         free(pt); 
    49         free(id); 
    50         return 1; 
    51     }
    52 
    53     for (int i = 0; i < num_thread; i++)
    54     { 
    55         id[i] = i; 
    56         if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0)
    57         { 
    58             printf("thread create failed!
    "); 
    59             return 1; 
    60         } 
    61     } 
    62     for (int i = 0; i < num_thread; i++)
    63     { 
    64         pthread_join(pt[i], NULL); 
    65     } // 释放资源 
    66 
    67     pthread_mutex_destroy(&mutex);
    68     free(pt); 
    69     free(id); 
    70     return 0; 
    71 }

    运行结果:

    屏幕输出:

    0
    1
    2
    3
    4

    输出文件(hello):

  • 相关阅读:
    MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第一部分)——IDiscoveryService
    MS CRM 2011的自定义和开发(7)——视图编辑器(第二部分)
    MS CRM 2011 SDK 5.06版本已经发布
    MS CRM 2011的自定义和开发(11)——插件(plugin)开发(一)
    近来遇到的MS CRM 2011方面的几个问题
    MS CRM 2011的自定义与开发(6)——表单编辑器(第二部分)
    Microsoft Dynamics CRM 2011中,Lookup字段的赋值
    MS CRM 2011的自定义和开发(6)——表单编辑器(第三部分)
    Visual Studio 目标框架造成 命名空间“Microsoft”中不存在类型或命名空间名称“Crm”。是否缺少程序集引用中错误的处理
    一步步学习Reporting Services(二) 在报表中使用简单的参数作为查询条件
  • 原文地址:https://www.cnblogs.com/xuelisheng/p/10132333.html
Copyright © 2011-2022 走看看