【发布时间】:2017-04-27 07:28:00
【问题描述】:
我正在编写一个需要一些输入的程序;一个目录,一个文件名和一些标志。该程序的目的是在给定目录中搜索给定文件。在搜索时,如果它找到另一个目录,它将打开该目录并继续在那里搜索。其中一个标志允许用户选择程序将使用多少线程来搜索文件。
目录存储在堆栈中,我遇到的问题是线程之间的同步。我目前正在使用互斥锁和定时等待条件。这意味着如果线程等待了一定时间并且存储目录的堆栈为空,则线程将结束。问题是,当只运行 2 个线程时,1 个线程可能会完成所有工作,即打开 400 个目录,而另一个打开 0 个。
所以我的问题是......我怎样才能以更好的方式同步我的线程?也许不使用定时等待条件?线程应该什么时候终止?
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <getopt.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
void search_func(char *path, char *name, int d, int f, int l);
void *thread_func(void *arg);
void push(char *data);
char* pop();
#define MAXLENGTH 1000
#define MAXSIZE 10000
#define WAIT_TIME_SECONDS 0.1
pthread_mutex_t lock;
pthread_cond_t count_threshold_cv;
struct stack
{
char stk[MAXSIZE][MAXLENGTH];
int top;
};
typedef struct stack STACK;
STACK s;
struct arg_keeper {
char **argv;
int argc;
int d;
int f;
int l;
};
int main(int argc, char **argv) {
if(argc < 3) {
fprintf(stderr, "Not enough arguments\n");
return 1;
}
char *xValue = NULL;
int x;
int d = 0;
int f = 0;
int l = 0;
int nrthr = 0;
opterr = 0;
int thread_count = 0;
int directory_exist = 0;
pthread_t tid[1024];
while ((x = getopt(argc, argv, "t:p:")) != -1) {
switch (x) {
case 't':
xValue = optarg;
if (*xValue == 'd') {
d = 1;
} else if (*xValue == 'f') {
f = 1;
} else if (*xValue == 'l') {
l = 1;
}
break;
case 'p':
nrthr = atoi(optarg);
if(nrthr == 0) {
fprintf(stderr, "Invalid thread count\n");
return 1;
}
break;
case '?':
if (isprint (optopt))
fprintf(stderr, "Unknown option '-%c'.\n",
optopt);
return 1;
default:
abort();
}
}
if (argc >= 3) {
int i;
for (i = optind; i < argc - 1; i++) {
directory_exist = 1;
push(argv[i]);
}
}
if(directory_exist == 0) {
fprintf(stderr, "No directories entered\n");
return 1;
}
struct arg_keeper * arg_struct = malloc(sizeof(*arg_struct));
arg_struct->argv = argv;
arg_struct->argc = argc;
arg_struct->d = d;
arg_struct->f = f;
arg_struct->l = l;
if(pthread_mutex_init(&lock, NULL) != 0) {
fprintf(stderr, "Mutex initialisation failed\n");
return 1;
}
if(pthread_cond_init(&count_threshold_cv, NULL) != 0) {
fprintf(stderr, "Condition variable initialisation failed\n");
return 1;
}
while(thread_count < nrthr - 1) {
if(pthread_create(&(tid[thread_count++]), NULL, thread_func,
arg_struct) != 0)
fprintf(stderr, "Can't create thread\n");
}
if(nrthr!=0)
thread_func(arg_struct);
else
thread_func(arg_struct);
int c;
for(c = 0; c < nrthr; c++) {
pthread_join(tid[c], NULL);
}
pthread_mutex_destroy(&lock);
free(arg_struct);
return 0;
}
void *thread_func(void *arg) {
int dirOpened = 0;
struct arg_keeper arg_struct = *(struct arg_keeper *)arg;
char *data;
pthread_mutex_lock(&lock);
struct timespec ts;
struct timeval tp;
while(1) {
gettimeofday(&tp, NULL);
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += WAIT_TIME_SECONDS;
if (pthread_cond_timedwait(&count_threshold_cv, &lock, &ts) == ETIMEDOUT) {
if (s.top) {
data = pop();
pthread_cond_signal(&count_threshold_cv);
dirOpened++;
search_func(data, arg_struct.argv[arg_struct.argc - 1], arg_struct.d,
arg_struct.f, arg_struct.l);
}
else
break;
}
}
pthread_mutex_unlock(&lock);
fprintf(stdout, "Thread with id %lu opened %d directories\n",
pthread_self(), dirOpened);
return NULL;
}
void search_func(char *inPath, char *testName, int d, int f, int l) {
char path[PATH_MAX];
strcpy(path, inPath);
struct dirent *pDirent;
DIR *pDir;
struct stat file_info;
if ((pDir = opendir(path)) == NULL) {
fprintf(stderr, "Error:'%s': %s\n", path, strerror(errno));
} else {
int v1;
int v2;
char *str1 = ".";
char *str2 = "..";
char name[PATH_MAX];
strcpy(name, testName);
char testPath[PATH_MAX];
strcpy(testPath, path);
char testPathLast[PATH_MAX];
strcpy(testPathLast, path);
while ((pDirent = readdir(pDir)) != NULL) {
if (strcmp(pDirent->d_name, name) == 0 && d == 0 &&
f == 0 && l == 0) {
if (path[strlen(path) - 1] != '/')
strcat(testPathLast, "/");
strcat(testPathLast, pDirent->d_name);
fprintf(stdout, "%s\n", testPathLast);
}
char testPath2[PATH_MAX];
strcpy(testPath2, testPath);
strcat(testPath2, "/");
strcat(testPath2, pDirent->d_name);
if (lstat(testPath2, &file_info) != 0)
fprintf(stderr, "lstat error2: %s\n",
strerror(errno));
if (d == 1) {
if (strcmp(pDirent->d_name, name)
== 0 && S_ISDIR(file_info.st_mode)) {
if (path[strlen(path) - 1] != '/')
strcat(testPathLast, "/");
strcat(testPathLast, pDirent->d_name);
fprintf(stdout, "%s\n", testPathLast);
}
}
if (f == 1) {
if (strcmp(pDirent->d_name, name)
== 0 && S_ISREG(file_info.st_mode)) {
if (path[strlen(path) - 1] != '/')
strcat(testPathLast, "/");
strcat(testPathLast, pDirent->d_name);
fprintf(stdout, "%s\n", testPathLast);
}
}
if (l == 1) {
if (strcmp(pDirent->d_name, name)
== 0 && S_ISLNK(file_info.st_mode)) {
if (path[strlen(path) - 1] != '/')
strcat(testPathLast, "/");
strcat(testPathLast, pDirent->d_name);
fprintf(stdout, "%s\n", testPathLast);
}
}
v1 = strcmp(pDirent->d_name, str1);
v2 = strcmp(pDirent->d_name, str2);
if ((v1 != 0 && v2 != 0) && S_ISDIR(file_info.st_mode)) {
strcpy(path, testPath);
strcpy(path, testPath);
if (path[strlen(path) - 1] != '/')
strcat(path, "/");
strcat(path, pDirent->d_name);
push(path);
}
}
closedir(pDir);
}
}
void push(char *data)
{
if(s.top == (MAXSIZE - 1)) {
fprintf(stderr, "Stack is full\n");
return;
}
else {
s.top = s.top + 1;
strcpy(&(s.stk[s.top][0]), data);
}
return;
}
char* pop()
{
char *data;
if(s.top == -1) {
fprintf(stderr, "Stack is empty\n");
return NULL;
}
else {
data = s.stk[s.top];
s.top = s.top - 1;
}
return data;
}
【问题讨论】:
-
互斥锁保护共享资源免受并发访问。这里的共享资源是什么。它是否受到互斥锁的安全保护?即:共享资源在任何情况下都不会被并发访问(不包括并发只读访问)?
-
我首先想到的是使用信号量和要搜索的目录列表。线程在信号量上等待要搜索的目录。当有一个时,它会搜索它,并将它在其中找到的目录添加到列表中,并发布信号量该次数。这只是生产者/消费者的情况,生产者和消费者线程是相同的。 (见link on WP)
标签: c multithreading synchronization pthreads