**已关闭。**此问题需要debugging details。它目前不接受回答。
编辑问题以包括desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
8天前关闭
Improve this question
我有一个函数,它在C中维护一个动态大小的数组。该程序读取一个文本文件,并创建一个列表,每个独特的词,以及这些词的频率。它有一个搜索功能,看起来像这样:
int vec_lsearch(vector* vec, char* target)
{
for(int i = 0; i < vec->size; i++) {
if(strcmp(vec->data[i].word, target) == 0) {
return i;
}
}
return -1;
}
当我的程序运行时,它有大约60%的时间发生segfaults。然而,它在Valgrind下运行时 * 从不 * 崩溃。使用GDB,我可以找到问题。它也只在我运行两个或更多线程时崩溃。以下是我的GDB日志:
Thread 3 "Evans_Griffin_H" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6af1700 (LWP 13341)]
__strcmp_ssse3 () at ../sysdeps/x86_64/multiarch/../strcmp.S:173
173 ../sysdeps/x86_64/multiarch/../strcmp.S: No such file or directory.
(gdb) bt
#0 __strcmp_ssse3 () at ../sysdeps/x86_64/multiarch/../strcmp.S:173
#1 0x0000555555555283 in vec_find (vec=0x555555758490, target=0x7ffff72f381b "incomprehensible")
at Evans_Griffin_HW4_main.c:153
#2 0x00005555555553f1 in count_words (arg=0x555555758500) at Evans_Griffin_HW4_main.c:193
#3 0x00007ffff7bbb6db in start_thread (arg=0x7ffff6af1700) at pthread_create.c:463
#4 0x00007ffff78e461f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) select-frame 1
(gdb) p vec->data[i]
$3 = {word = 0x7ffff0002000 "played", freq = 1}
(gdb) p target
$4 = 0x7ffff72f381b "incomprehensible"
(gdb) p vec->data[i].word
$5 = 0x7ffff0002000 "played"
(gdb) p vec->data[i].word[6]
$7 = 0 '\000'
(gdb) p target[16]
$8 = 0 '\000'
据我所知,这两个字符串似乎都有效。我在插入和更新数据时使用互斥锁,但在使用strcmp时不使用(尽管我在这里尝试锁定线程,但没有区别)。有人能帮我弄明白为什么我的程序会崩溃吗?
编辑:由于学术诚信政策,我不能随意提供我的程序的完整源代码。我已经包括了一些更多的片段,希望是有帮助的。
typedef struct {
char* word;
int freq;
} word_freq;
typedef struct {
word_freq* data;
size_t size;
size_t capacity;
} vector;
void vec_push(vector* vec, char* e)
{
word_freq wf;
wf.freq = 1;
wf.word = malloc(strlen(e) + 1);
strcpy(wf.word, e);
vec->data[vec->size++] = wf;
// if vector is at capacity, realloc to double its capacity
if (vec->size == vec->capacity) {
vec->capacity *= 2;
vec->data = realloc(vec->data, vec->capacity * sizeof(word_freq));
}
if (vec->data[vec->size - 1].word == NULL) {
printf("Error inserting %s\n", e);
}
}
void* count_words(void* arg)
{
job_info* info = arg;
vector* word_vec = info->words; // vector of word_freq structs
char* buf = info->buffer;
int thread_num = info->thread_num;
char* saveptr;
char* token = strtok_r(buf, delim, &saveptr);
while(token != NULL) {
trim_word(token);
if(strlen(token) >= MIN_STRING_LENGTH && strlen(token) <= MAX_STRING_LENGTH) {
// because the size of the vector may change, must lock the thread before
// accessing it
if (pthread_mutex_lock(&info->mutex)) {
perror("mutex lock");
}
int index = vec_lsearch(word_vec, token);
if(index != -1) {
word_vec->data[index].freq++;
} else {
vec_push(word_vec, token);
}
vec_health(word_vec);
if (pthread_mutex_unlock(&info->mutex)) {
perror("mutex unlock");
}
}
token = strtok_r(NULL, delim, &saveptr);
}
}
// given input string, convert it to lower case and discard any non-alphabet (a-z and A-Z) characters
void trim_word(char* in)
{
int i = 0;
int j = 0;
char c;
while (( c = in[i++]) != '\0') {
if (isalpha(c)) {
in[j++] = tolower(c);
}
}
in[j] = '\0';
}
int vec_health(vector* vec)
{
if (vec->data == NULL) {
return 1;
}
for(int i = 0; i < vec->size; i++) {
if (vec->data[i].word == NULL) {
fprintf(stderr, "data[%d] is null!\n", i);
return 2;
}
}
return 0;
}
我写了一个新的测试函数vec_health
,它显示了我的结构体的某些成员是NULL,尽管我仍然不确定这是怎么回事。感谢@solomon-slow的启发性评论。vec_health
将在运行时警告我某些对象具有空值,例如
data[3583] is null!
data[6143] is null!
但是我在广发行检查的时候,好像没什么问题
(gdb) p vec->data[3583]
$2 = {word = 0x7fffe800dfc0 "bucket", freq = 1}
(gdb) p vec->data[6143]
$3 = {word = 0x7fffe80184a0 "defending", freq = 7}
2条答案
按热度按时间1rhkuytd1#
这是一个延伸的评论。这不是一个“答案”。
如果vector只包含指向字符串的有效指针,并且如果给定的
target
是指向字符串的有效指针,则不应该发生segfault。所以,要么target
有问题,要么向量有问题。使用GDB.据我所知,这两个字符串似乎都是有效的。
多处理器机器上的线程可能很棘手。您在GDB中看到的内容可能与
vec_find
函数运行时看到的内容不同。我在插入和更新数据时使用互斥锁,但在使用strcmp时不使用。
这是一个“严重”的问题。是什么阻止你的
vec_find
函数在其他线程添加另一个字符串的时候试图访问向量?谁知道那个时候矢量会处于什么状态?(提示:* 你 * 不知道,如果你不熟悉你的程序调用的库代码。在
vec_find
中没有任何锁定,您的程序是无效的。说这些都没意义..
“锁定线程”是什么意思?你有没有一个版本的
vec_find
锁定 * 相同的互斥量 *,其他线程正在使用?如果不是同一个互斥体就不算数。如果你想要一个有意义的答案,那么你应该用更多的代码来更新它。显示修改vector的所有代码。显示“锁定线程”的
vec_find
版本。解释哪个线程做什么。o4tp2gmn2#
我更新了我的代码以使用多线程。我不是多线程方面的Maven,但我建议你在所有会修改你的vector结构或其中数据的写操作上使用互斥锁,比如你的vec_push函数。只读操作应该是非关键的,比如vec_find。
下面是我更新的代码。我希望它能帮助你。