论读写锁(pthread_rwlock_t)的适用范围

本文探讨了读写锁的应用场景及其实现原理,提出在保证数据完整性时,可根据数据的特性选择是否使用读写锁。并通过实验验证了特定类型变量在多线程环境下无需读写锁也能保持数据完整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结论

在需要频繁操作一个内存数量大于其单个类型所占空间大小的时候,为了保证数据的完整性以及高性能,采用读写锁。在数据具有一定唯X性时(我发明的词),在多线程数据类型已经保证完整性时,可以不用读写锁。其中唯X指的是唯二、唯三、唯四等除乱码以外的值。其中具有唯X性的内存具有以下特点。(有很多自创词汇,均有解释,请勿烦恼)

1是一个单独的变量。

一个单独的变量相对的就是一个集合变量,一个int值是一个单独的变量,但是一个int[]的数组就是一个集合变量,不过数组名也可以作为指针,一个指针却是一个单独变量。

2与系统位数无关。

也就是说在32位系统上的8字节类型double,也是一个单独变量,这是对上一特点的补充说明。

3是系统默认的变量类型

其本质必须是系统默认变量类型。因为只有系统默认类型才会一次性改变。

说明

用作测试的代码放在了最后
先说结论是因为从最初打算做修改到最后验证完自己的推论整个过程过于复杂庞大,所以为了提高效率,将结论放在了最前面。
思考这个问题来源是对以前一份线程池的改写,因为其中使用了大量的读写锁,虽然我上一篇博客用宏大大缩减了代码篇幅,但是电脑的工作量并没有缩减。仔细看过了读写锁所使用的地方,发现锁定的内存中的值在整个线程池中,并不是完全要求唯一的,有些是唯二、唯三、甚至唯四,但是不允许出现乱码。最初只是想能不能去掉读写锁,在繁杂的逻辑中,不用繁杂的加锁与解锁。在阅读一些机制的时候。

问题

为什么要用读写锁,什么时候可以不用读写锁。
这两个问题是我最初找到的突破口(我不喜欢将为解决“问题”而产生“问题”称之为问题,而是突破口。)。

解决

为什么用读写锁,是为了保证数据完整性,且能高效的读写,因为互斥锁也能保证完整性,但是处理这种业务而采用互斥锁显然效率不高。
什么时候可以不用读写锁,在保证数据完整性的情况下,修改前和修改后的数据都可以作为有用值读取,即有用值唯二,可以不唯一。但是切记不可以是修改前后混杂的数据。

问题

什么样的数据在多核多(硬)多线程(软)上保证唯X?

信息

数据的改变死内存段位上值1与0的互换,一个系统有其机械码执行位数,虽然现在的电脑有64位和32位之分,但是其执行的机械码还是32位的,但是64位的寻址是64位的,所以在64位系统上指针大小其实是8字节。

推论

因为一次性进入CPU的机械码是固定的位数,所以在位数小于或等于特定位数的时候,值是一次性改变的,即改变的过程不可被打断。

问题:

在64位机械上机械码是32位但是指针是8个字节,是否是一次性改变的?

推论:

是一次性改变的,一个地址算作是一个不可分割机械码组,修改时不可被打断。内存会对此做保证。

查阅资料验证:

新发现,虽然一二级缓存独立三级共享,但是上了读写锁,数据键不被放入缓存,而是CPU从内存中找。

猜测

如果不适用锁,是否可以放在三级贡献缓存内提高效率:这一点并么有去得到验证。还请大佬帮忙解答。

整理需要测试测共变量

系统位数,程序变量选择。系统采用英特尔64位i7-3840qm与32位骁龙801
测试数据类型char* 、int、double、char[]。指针主要是为了测64位系统,int是系统位数和类型位数验证,double是为了验证一个数据类型是一组完整的机械码不可被打断。char[]是为了验证非单一变量,即多个字节非一组成一个非单一变量。

测试结果

char[]一秒内直接失败,内容混乱单在单一变量上,值未出现错误。其他三个变量在两次三小测试和一次一小时多的测试中,均未报错。

代码

 19 #include<stdio.h>
 20 #include<string.h>
 21 #include<pthread.h>
 22 #include<signal.h>
 23 #include<time.h>
 24 #include<unistd.h>
 25 char char_a,char_b;
 26 char*pto_char;
 27 int to_int;
 28 double to_double=0.12345678987654321;
 29 char p_char[10]="hello";
 30 void dop1()
 31 {
 32     while(1)
 33     if(pto_char==&char_a)
 34         pto_char=&char_b;
 35 }
 36 void dop2()
 37 {
 38     while(1)
 39     if(pto_char==&char_b)
 40         pto_char=&char_a;
 41 }
 42 void dop3()
 43 {
 44 
 45     while(1)
 46     {//因为存在比对对一个时是第二个的值,在比对第二个时有变成了第一个,导致if判断为两个都不等于
 47         char*p_test=pto_char;
 48         if(*p_test!=char_a&&*p_test!=char_b)
 49         {
 50             printf("pto_char=%d,%d\n",p_test,*p_test);
 51             exit(1);
 52         }
 53     }
 54 }
 55 void doint1()
 56 {
 57     while(1)
 58     if(to_int==0xaaaaaaaa)
 59         to_int=0x55555555;
 60 }
 61 void doint2()
 62 {
 63     while(1)
 64     if(to_int==0x55555555)
 65         to_int=0xaaaaaaaa;
 66 }
 67 void doint3()
 68 {
 69     while(1)
 70     {
 71         int test=to_int;
 72         if(test!=0x55555555&&test!=0xaaaaaaaa)
 73         {
 74             printf("to_int=%d\n",test);
 75             exit(1);
 76         }
 77     }
 78 }
 79 void dodouble1()
 80 {
 81     while(1)
 82     if(to_double==0.12345678987654321)
 83         to_double=987654321012345678.9;
 84 }
 85 void dodouble2()
 86 {
 87     while(1)
 88     if(to_double==987654321012345678.9)
 89         to_double=0.12345678987654321;
 90 }
 91 void dodouble3()
 92 {
 93     while(1)
 94     {
 95         double test=to_double;
 96         if(test!=0.12345678987654321&&test!=987654321012345678.9)
 97         {
 98             printf("to_double=%d\n",test);
 99             exit(1);
100         }
101     }
102 }
103 void dop_char1()
104 {
105     while(1)
106     if(!strcmp(p_char,"hello"))
107         strcpy(p_char,"world");
108 }
109 void dop_char2()
110 {
111     while(1)
112     if(!strcmp(p_char,"world"))
113         strcpy(p_char,"hello");
114 }
115 void dop_char3()
116 {
117     while(1)
118     {
119         char test[10];
120         strcpy(test,p_char);
121         if(strcmp(test,"hello")&&strcmp(test,"world"))
122         {
123             printf("p_char=%s\n",test);
124             exit(1);
125         }
126     }
127 }
128 void printf_time()
129 {
130     struct tm *t;
131     time_t tt;
132     time(&tt);
133     t = localtime(&tt);
134     printf("%4d年%02d月%02d日 %02d:%02d:%02d\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
135 }
136 int main()
137 {
138     printf_time();
139     printf("sizeof pto_char:=%d\n",sizeof(pto_char));
140     printf("sizeof int:=%d\n",sizeof(int));
141     printf("sizeof double:=%d\n",sizeof(double));
142     printf("sizeof p_char:=%d\n",sizeof(p_char));
143     char_a=1;
144     char_b=2;
145     to_int=0xaaaaaaaa;
146     pto_char=&char_a;
146     pto_char=&char_a;
147     double double_a=0.12345678987654321;
148     double double_b=987654321012345678.9;
149     printf("%d,%d\n",&char_a,&char_b);
150     int c;
151     memcpy(&c,&double_a,4);
152     printf("%d\n",c);
153     memcpy(&c,&double_b,4);
154     printf("%d\n",c);
155     pthread_t pthread[12];
156     pthread_create(pthread,NULL,dop1,NULL);
157     pthread_create(pthread+1,NULL,dop2,NULL);
158     pthread_create(pthread+2,NULL,dop3,NULL);
159     pthread_create(pthread+3,NULL,doint1,NULL);
160     pthread_create(pthread+4,NULL,doint2,NULL);
161     pthread_create(pthread+5,NULL,doint3,NULL);
162     pthread_create(pthread+6,NULL,dodouble1,NULL);
163     pthread_create(pthread+7,NULL,dodouble2,NULL);
164     pthread_create(pthread+8,NULL,dodouble3,NULL);
165 /*  pthread_create(pthread+8,NULL,dop_char1,NULL);
166     pthread_create(pthread+10,NULL,dop_char2,NULL);
167     pthread_create(pthread+11,NULL,dop_char3,NULL);*/
168     while(1)
169     {
170         sleep(60);
171         printf_time();
172     }
173     return 0;
174 }

最后还是想问一下大佬

有没有大佬知道加了读写锁,是否三级缓存只是内存的拷贝。三级缓存共享,是否能修改缓存内的值,后修改内存值。以及一个值在内存中,到这个值改变的完整步骤。

#include <stdio.h> #include <pthread.h> #include <unistd.h> //临界资源,应该使用volatile进行修饰,防止编译器对该变量进行优化 volatile int data = 10; //读写锁对象,必须是全局变量 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; //子线程B的任务,格式是固定的 void * task_B(void *arg) { //线程任务应该是死循环,并且不会退出 while(1) { //获取读操作的锁 pthread_rwlock_rdlock(&rwlock); //对临界资源进行读操作 printf("I am Thread_B,data = %d\n",data); sleep(1); //释放读操作的锁 pthread_rwlock_unlock(&rwlock); } } //子线程C的任务,格式是固定的 void * task_C(void *arg) { //线程任务应该是死循环,并且不会退出 while(1) { //获取读操作的锁 pthread_rwlock_rdlock(&rwlock); //对临界资源进行读操作 printf("I am Thread_C,data = %d\n",data); sleep(1); //释放读操作的锁 pthread_rwlock_unlock(&rwlock); } } //主线程 A int main(int argc, char const *argv[]) { //1.对创建的读写锁对象进行初始化 pthread_rwlock_init(&rwlock,NULL); //2.创建子线程 pthread_t thread_B; pthread_t thread_C; pthread_create(&thread_B,NULL,task_B,NULL); pthread_create(&thread_C,NULL,task_C,NULL); //3.进入死循环,主线程需要对临界资源进行修改 while(1) { //主线程会阻塞等待,10s会解除阻塞 sleep(10); //获取写操作的锁 pthread_rwlock_wrlock(&rwlock); //对临界资源进行读操作 data += 20; printf("I am main_Thread,data = %d\n",data); sleep(5); //释放写操作的锁 pthread_rwlock_unlock(&rwlock); } return 0; }
最新发布
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值