Linux下多线程编程之——线程互斥

一、互斥对象基础

  互斥对象其实就是锁,用来邦正共享资源操作的完整性,每个对象都对应与一个可称为“互斥锁”的标记。该标记用来保证在人一个时都只能有一个线程访问该对象,资源通常时内存、文件句柄等。线程访问某资源,需要先获得互斥量,对其加锁;加过锁的资源如果需要被其他线程访问,通过互斥量获取资源也被锁定,只能阻塞等待,直至占有该资源的线程解锁为止。

二、锁的操作主要有加锁、解锁和尝试加锁等,分别通过函数:

  1、int pthread_mutex_lock(pthread_mutex_t *mutex);     加锁 

  2、int pthread_mutex_trylock(pthread_mutex_t *mutex); 尝试加锁

  3、int pthread_mutex_unlock(pthread_mutex_t *mutex); 解锁

三、代码test7_7.c

 1 //This is c program code!
 2 /* *=+=+=+=+* *** *=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
 3   * 文档信息: *** :~/test7_7.c
 4   * 版权声明: *** :(魎魍魅魑)MIT
 5   * 联络信箱: *** :guochaoxxl@163.com
 6   * 创建时间: *** :2020年11月17日的下午09:18
 7   * 文档用途: *** :数据结构与算法分析-c语言描述
 8   * 作者信息: *** :guochaoxxl(http://cnblogs.com/guochaoxxl)
 9   * 修订时间: *** :2020年第46周 11月17日 星期二 下午09:18 (第322天)
10   * 文件描述: *** :自行添加
11  * *+=+=+=+=* *** *+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*/
12 #include <stdio.h>
13 #include <unistd.h>                                                                     
14 #include <pthread.h>
15 
16 #define MAXS 1000 
17 
18 pthread_mutex_t mutex;
19 double myJq[MAXS + 1];
20 int max;
21 
22 void *myComp(void *iData){
23     int i;
24     pthread_mutex_lock(&mutex);
25     myJq[0]++;
26     i = myJq[0];
27     pthread_mutex_unlock(&mutex);
28     myJq[i] = (1/(double)i);
29     printf("1/%d finished, result %.10f
", i, myJq[i]);
30 }
31 
32 void *myComprint(void *iData){
33     int maxI;
34     double jq;
35 
36     while(1){
37         sleep(1);
38         pthread_mutex_lock(&mutex);
39         maxI = myJq[0];
40         pthread_mutex_unlock(&mutex);
41         if(maxI >= max){
42             for(int i = 1; i <= max; i++){
43                 jq += myJq[i];
44                 printf("%.10f added
", myJq[i]);
45             }
46             printf("result: %.10f
", jq);
47             break;
48         }
49     }
50 }
51 
52 int main(int argc, char **argv)
53 {
54     pthread_t threads[MAXS + 1];
55     void *status;
56     printf("please input an integer: (<= %d)", MAXS);
57     while(scanf("%d", &max), max > MAXS){
58         printf("please input an integer: (<= %d)", MAXS);
59     };
60     myJq[0] = 0;
61     pthread_create(&(threads[0]), NULL, myComprint, NULL);
62     for(int i = 1; i <= max; i++){
63         pthread_create(&(threads[i]), NULL, myComp, NULL);
64     }
65     sleep(1);
66     for(int i = 0; i <= max; i++){
67         pthread_join(threads[i], NULL);
68     }
69     pthread_mutex_destroy(&mutex);
70 
71     return 0;
72 }  

   调用pthread_mutex_lock函数返回后,互斥锁被锁定。线程调用该函数对互斥锁上锁,若互斥锁已被其他线程锁定,则调用互斥锁的线程将被阻塞,直到互斥锁解锁位置。

四、共享内存区

  共享内存区允许多个不相关的进程去访问同一部分逻辑内存。需要多个进程间共享数据时,共享内存是一种高效的解决办法。mmap()函数通常将一个文件或共享内存区对象映射到调用进程的地址空间中。主要用途:

  1、用普通文件以提供内存映射I/O

  2、使用特殊文件以提供匿名内存映射

  3、使用shm_open来提供无父子关系的进程间共享内存区域

  参数说明:

  1、第1个参数addr:指向映射存储区域的起始地址,常常设置为NULL,表示由系统选择该映射区的起始地址

  2、第2个参数len:映射的字节数目

  3、第3个参数prot:对映射存储区的保护要求,PORT_NONE  PORT_READ  PORT_WRITE  PORT_EXEC,可以是单个,也可以多个组合

  4、第4个参数flag:表示lag标志位

  5、第5个参数filedes:表示被映射文件的描述符,将该文件映射到一个地址空间之前,需要先打开该文件

  6、第6个参数off:表示要映射的字节在文件中的起始偏移量

与mmap()函数对应的munmap()函数是解除存储映射

  1、第1个参数addr:映射存储区的起始地址

  2、第2个参数len:映射的字节数目

shm_open():打开或创建一个共享内存区

  1、第1个参数name:共享内存区域的名字

  2、第2个参数oflag:为标志位

  3、第3个参数mode:为权限位

ftruncate():普通文件或共享内存区大小可以通过该函数调整

  建立共享内存区对象主要包括2个步骤:

  一、指定一个名字参数调用shm_open,创建一个新的共享内存区对象,或者打开一个已经存在的共享内存对象

  二、调用mmap将这共享内存区映射到调用进程的地址空间,传递给shm_open的名字参数,就可以被需要共享内存区的其他进程调用了

五、互斥对象共享:

  互斥对象既可以是进程内的变量,也可以系统中进程间的变量。如果想要在多个进程中的线程之间共享互斥对象,可以在共享内存中创建互斥对象,pthread_mutexattr_setpshared函数用来设置互斥锁变量俄作用域;第2个参数设置为PTHREAD_PROCESS_PRIVATE,表示互斥变量只能被同一个进程创建的线程进行处理,若设置为PTHREAD_PROCESS_SHARED,表示该互斥变量可被多个进程的线程所共享

六、代码test7_8.c

 1 //This is c program code!
 2 /* *=+=+=+=+* *** *=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
 3   * 文档信息: *** :~/test7_8.c
 4   * 版权声明: *** :(魎魍魅魑)MIT
 5   * 联络信箱: *** :guochaoxxl@163.com
 6   * 创建时间: *** :2020年11月17日的下午09:50
 7   * 文档用途: *** :数据结构与算法分析-c语言描述
 8   * 作者信息: *** :guochaoxxl(http://cnblogs.com/guochaoxxl)
 9   * 修订时间: *** :2020年第46周 11月17日 星期二 下午09:50 (第322天)
10   * 文件描述: *** :自行添加
11  * *+=+=+=+=* *** *+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*/
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <pthread.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/stat.h>
18 #include <sys/mman.h>
19 
20 int main(int argc, char **argv)
21 {
22     int *x;
23     int rt;
24     int shm_id;
25     char *addNum = "myAdd";
26     char *ptr;
27     pthread_mutex_t mutex;
28     pthread_mutexattr_t mutexattr;
29     pthread_mutexattr_init(&mutexattr);
30     pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
31     rt = fork();
32     if(rt == 0){
33         shm_id = shm_open(addNum, O_RDWR, 0);
34         ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, shm_id, 0);
35         x = (int *)ptr;
36         for(int i = 0; i < 10; i++){
37             pthread_mutex_lock(&mutex);
38             (*x)++;
39             printf("x++: %d
", *x);
40             pthread_mutex_unlock(&mutex);
41             sleep(1);
42         }
43     }else{
44         shm_id = shm_open(addNum, O_RDWR|O_CREAT, 0644);
45         ftruncate(shm_id, sizeof(int));
46         ptr == mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, shm_id, 0);
47         x = (int *)ptr;
48         for(int i = 0; i < 10; i++){
49             pthread_mutex_lock(&mutex);
50             (*x) += 2;
51             printf("x += 2: %d
", 2* *x);                                              
52             pthread_mutex_unlock(&mutex);
53             sleep(1);
54         }
55     }
56     shm_unlink(addNum);
57     munmap(ptr, sizeof(int));
58 
59     return 0;
60 }

  编译是加上库链接-lrt:

gcc test7_8.c -o test7_8  -lpthread -lrt

  代码不难,不多啰嗦。

原文地址:https://www.cnblogs.com/guochaoxxl/p/14002502.html