【发布时间】:2019-05-31 21:47:01
【问题描述】:
我正在尝试编写一个使用线程的代码,以查找名称中包含特定字符串的文件。
我的代码在大多数情况下都能正常工作。在某些特定情况下,线程由于某种原因无法获取锁。
我非常努力地调试(使用打印,正如您在代码中看到的那样)但我找不到问题。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
void* threadFunction(void* searchTerm);
bool scanDirName(char * path, char * searchTerm);
int numOfThreads;
pthread_mutex_t qlock;
pthread_cond_t cond;
int count;
int matchingFiles;
struct Node {
char* data;
struct Node* next;
};
// Two global variables to store an address of front and rear nodes.
struct Node* front = NULL;
struct Node* rear = NULL;
// To Enqueue an integer
void Enqueue(char* x) {
/* printf("\nhere\n");*/
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->data =x;
temp->next = NULL;
if(front == NULL && rear == NULL){
front = rear = temp;
pthread_cond_signal(&cond);
return;
}
rear->next = temp;
rear = temp;
}
// To Dequeue an integer.
char* Dequeue() {
struct Node* temp = front;
if(front == NULL) {
return NULL;
}
char* data;
data = front->data;
if(front == rear) {
front = rear = NULL;
}
else {
front = front->next;
}
// printf("\nfreeing %p, %s\n", temp, temp->data);
free(temp);
return data;
}
void* threadFunction(void* st) {
bool isFinished;
isFinished = false;
pthread_mutex_lock(&qlock);
while (true) {
char *filepath;
char *searchTerm;
searchTerm = (char *) st;
filepath = Dequeue();
pthread_mutex_unlock(&qlock);
if (filepath == NULL) {
printf("%ld waiting for lock \n",(long) pthread_self());
pthread_mutex_lock(&qlock);
count++;
if (isFinished) {
printf("%ld waking u up, we found %d items!\n",(long) pthread_self(), matchingFiles);
pthread_cond_broadcast(&cond);
if (count == numOfThreads) {
printf("Thread exited: %ld\n", (long) pthread_self());
pthread_mutex_unlock(&qlock);
pthread_exit((void*)0);
}
}
isFinished = false;
printf("%ld going to sleep\n",(long) pthread_self());
pthread_cond_wait(&cond, &qlock);
printf("%ld Woke up, try to compare %d == %d\n",(long) pthread_self(), count, numOfThreads);
if (count == numOfThreads) {
printf("Thread exited: %ld\n", (long) pthread_self());
pthread_mutex_unlock(&qlock);
pthread_exit((void*)1);
}
printf("%ld compare failed \n",(long) pthread_self());
count--;
}
else {
printf("%ld deq 1 item \n",(long) pthread_self());
isFinished = scanDirName(filepath, searchTerm);
}
}
}
bool scanDirName(char * path, char * searchTerm){
DIR * d = opendir(path); // open the path
char* str3;
if(d==NULL) return false; // if was not able return
;
struct dirent * dir; // for the directory entries
while ((dir = readdir(d)) != NULL) // if we were able to read somehting from the directory
{
printf("%ld STARTED A ROUND!\n",(long) pthread_self());
if(dir-> d_type == DT_DIR){ //
if (dir->d_type == DT_DIR && strcmp(dir->d_name, ".") != 0 & strcmp(dir->d_name, "..") != 0) // if it is a directory
{
str3 = malloc((1+strlen("/")+ strlen(path)+ strlen(dir->d_name))*sizeof(char));
if (!str3){
return false;
}
strcpy(str3, path);
strcat(str3, "/");
strcat(str3, dir->d_name);
// printf("\n---\n%s\n---\n",str3);
printf("%ld waiting for lock in func \n",(long) pthread_self());
pthread_mutex_lock(&qlock);
printf("%ld wake threads \n",(long) pthread_self());
Enqueue(str3);
pthread_cond_signal(&cond);
printf("%ld enq \n",(long) pthread_self());
pthread_mutex_unlock(&qlock);
printf("%ld locks gone \n",(long) pthread_self());
}
}
else if(dir-> d_type == DT_REG){ //
if(strstr(dir->d_name, searchTerm)){
matchingFiles++;
/*printf("%s/%s\n", path, dir->d_name);*/
}
}
printf("%ld finished A ROUND!\n",(long) pthread_self());
}
printf("%ld finished scanning!\n",(long) pthread_self());
fflush(stdout);
closedir(d); // finally close the directory
if (count == numOfThreads-1) {
return true;
}
return false;
}
int main(int argc, char* argv[]){
count = 0;
pthread_mutex_init(&qlock, NULL);
pthread_cond_init(&cond, NULL);
matchingFiles = 0;
if (argc != 4){
printf("ERROR\n");
exit(1);
}
char* rootSearchDir = argv[1];
char* searchTerm = argv[2];
int threadsNumber = atoi(argv[3]);
pthread_t threadsCollection[threadsNumber];
Enqueue(rootSearchDir);
numOfThreads = threadsNumber;
int i;
for (i=0; i<threadsNumber; i++){
if(pthread_create(&threadsCollection[i], NULL, threadFunction, (void*)searchTerm)) {
fprintf(stderr, "Error creating thread\n");
pthread_mutex_destroy(&qlock);
return 1;
}
}
int rc;
for (i=0; i<threadsNumber; i++){
rc = pthread_join((threadsCollection[i]), NULL);
if(rc) {
fprintf(stderr, "Error joining thread, %d\n", rc);
pthread_mutex_destroy(&qlock);
return 1;
}
}
}
我已附上所有代码(可能很重要),但我怀疑问题出在 scanDirName 或 threadFunction 中。
--- 编辑 ---
我发现了问题。我的锁有逻辑问题,修复它。 谢谢大家!
【问题讨论】:
-
在
isFinished = false;之后和if (count == numOfThreads)之前对pthread_cond_wait的调用中,线程到底在等待什么?如果它正在等待对Enqueue的呼叫,那么您怎么知道这还没有发生而您正在等待已经发生的事情? -
@DavidSchwartz 线程正在等待,直到有人向此条件变量发送信号\广播。我这样做是因为我不想忙于等待并浪费 CPU 时间。
-
使用 gdb 和
thr a a bt进行调试可能会产生比 printf 更好的结果。 -
@DarkSkylo 你不能那样使用条件变量。它们是无状态的,所以你不能等待它们改变状态。迟早,这会咬你。
标签: c multithreading pthreads locking