结论
在需要频繁操作一个内存数量大于其单个类型所占空间大小的时候,为了保证数据的完整性以及高性能,采用读写锁。在数据具有一定唯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 }
最后还是想问一下大佬
有没有大佬知道加了读写锁,是否三级缓存只是内存的拷贝。三级缓存共享,是否能修改缓存内的值,后修改内存值。以及一个值在内存中,到这个值改变的完整步骤。