我真的有一种奇怪的情况。我正在使用涉及char *字符串的所有细节内存来制作Linux多线程C应用程序,而且我陷入了一个非常奇怪的位置。
基本上,使用POSIX线程,我正在读取和写入二维char数组,但它有不寻常的错误。您知道我已经对他们单独访问的内容进行了大量测试,并且他们不会读取其他线程的数据,更不用说写给其他人了。当使用数组的最后一个线程改变它的数组部分时,它似乎改变了它的数组的最后几个字符并在那里放置了我不知道它们可能在那里的字符;主要是印有黑钻石问号的东西。
我使用valgrind和GDB,但他们并没有真正帮助。据我所知,一切都应该奏效。 Valgrind告诉我,我没有释放所有东西。
我知道所有这些听起来都是不合情理的,但这里有点奇怪:如果我用电围栏编译我的程序,那么一切正常。 Valgrind告诉我,我正在释放所有东西,而且根本没有记忆错误,正如我认为的那样。它绝对完美无缺!
所以,我想我的问题是,为什么我的程序在用电围栏编译时工作正常?
(另外作为一个附带问题,需要采取哪些措施来确保100%“线程安全”代码?)
答案 0 :(得分:2)
听起来你正在诋毁你的数据结构。尝试将金丝雀放在数组的开头和结尾,打开GDB,然后在金丝雀上写下断点。
canary是一个永远不应该更改的const值 - 它的唯一目的是检测内存损坏,如果它被覆盖。例如:
int the_size_i_need;
char* array = malloc((the_size_i_need + 2) * sizeof(char));
array[0] = 0xAA;
array[the_size_i_need+1] = 0xFF;
char* real_array = array+1;
/* Do some stuff here using real_array */
if (array[0] != 0xAA || array[the_size_i_need+1] != 0xFF) {
printf("Oh noes! We're corrupted\n");
}
答案 1 :(得分:2)
电子围栏为每个分配分配页面,我至少听过两次。它使用OS分页机制来检查分配之外的访问。这意味着如果你想要一个新的14个字符的数组,你最终会得到一个全新的页面来保存它,比如8k。大部分页面未使用,但您可以通过观察使用哪些页面来检测错误访问。我可以想象,如果一个问题越过警卫,你就会有更多的额外空间,你就不会看到错误。
如果您没有错误的访问权限,而是由于两个线程未正确锁定而导致损坏,则efence将无法检测到它。 efence也可能保留指向已分配内存的指针,愚弄valgrind报告没有问题。您应该使用--show-reachable=yes
标志运行valgrind,并查看运行结束时无人认领的内容。
答案 2 :(得分:0)
天啊,我很抱歉。我已经解决了:每个线程都有一个变量给他们的答案,但我没有把它定义为零,它包含2个有趣的字符。也许电栅栏malloc()像calloc()一样分配'归零'内存,但标准的malloc()当然不会。