1

セマフォと相互排除の概念は初めてです。マルチスレッドを使用して、ディレクトリを介してファイル内を再帰的にテキスト検索することになっています。スレッド数はユーザーが指定します。

このコードの問題は、1 つのディレクトリを通過してから待機することです。何が問題なのかわかりません。セグメンテーション違反エラーが発生しています。なぜこれが起こっているのか分かりません。

#include <iostream>
#include <sys/wait.h>
#include <sys/types.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fstream>
#include <limits.h>
#include <stdlib.h>
#include <semaphore.h>
using namespace std;


#include <stdio.h>

int iDirectories=0;

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
sem_t semaphore1;
char searchStringThread[PATH_MAX];

int directories=0;


class directoryQueue
{
private:
struct Node
{
    char directoryPath[PATH_MAX];
    Node *next;
};
Node *front;
Node *rear;
Node *nodeCount;

public:

    directoryQueue(void)
    {
        front=NULL;
        rear=NULL;
        nodeCount=0;
    }


    void Enqueue(char array[PATH_MAX])

    {
        Node *newNode;
        newNode=new Node;

        strcpy(newNode->directoryPath,array);
        newNode->next=NULL;
        if(isEmpty())
        {
            front=newNode;
            rear=newNode;
        }
        else
        {
            rear->next=newNode;
            rear=newNode;
        }
        nodeCount++;
    }
    char * Dequeue(void)
    {
        Node *temp;

        if (isEmpty())
            cout << "Error ! Empty Queue "<<endl;
        else
        {
            char *deque;
            deque=new char[PATH_MAX];
            strcpy(deque,front->directoryPath);

            temp = front->next;
            front = temp;
            nodeCount--;
            return deque;
        }

    }

    bool isEmpty(void)
    {
        if(nodeCount)
            return false;
        else
            return true;
    }

    void makeNull(void)
    {
        while(!isEmpty())
        {
            Dequeue();
        }
    }

    ~directoryQueue(void)
    {
        makeNull();
    }
};
directoryQueue saveDirectory;



void *threadHandler(void *)
{
int thpath_length;
char thPath[PATH_MAX];
char saveITDirectory[PATH_MAX];
char itDirectory[PATH_MAX];
int threadCount;
struct dirent *iWalker;
DIR *iDirectory;
pthread_mutex_lock(&mutex);
threadCount=iDirectories++;
pthread_mutex_unlock(&mutex);
sem_wait(&semaphore1);
pthread_mutex_lock(&mutex);
strcpy(itDirectory,saveDirectory.Dequeue());
pthread_mutex_unlock(&mutex);

iDirectory=opendir(itDirectory);
if(iDirectory==NULL)
{
    cout<<"Error"<<endl;
    cout<<itDirectory<<"  Cannot be Opened"<<endl;
    exit(10000);
}
while((iWalker=readdir(iDirectory)) !=NULL)
{
    if(iWalker->d_type==DT_REG)
    {




        strcpy(saveITDirectory,iWalker->d_name);
        cout<<itDirectory<<"/"<<endl;
        if (strcmp (saveITDirectory, "..") == 0 ||
            strcmp (saveITDirectory, ".") == 0) 
        {
            continue;
        }
        else
        {


            thpath_length = snprintf(thPath,PATH_MAX,"%s/%s",itDirectory,saveITDirectory);

            cout<<thPath<<endl;
            if (thpath_length >= PATH_MAX) 
            {
                cout<<"Path is too long"<<endl;
                exit (1000);
            }
            ifstream openFile;
            openFile.open(thPath);
            char line[1500];
            int currentLine = 0;
            if (openFile.is_open()) {
                while (openFile.good()) {
                    currentLine++;
                    openFile.getline(line, 1500);
                    if (strstr(line, searchStringThread) != NULL){
                        cout<<thPath<<": "<<currentLine<<": "<<line<<endl;
                        cout<<"This was performed by Thread no. "<<threadCount<<endl;
                        cout<<"ID :"<<pthread_self();
                    }
                }
            }
            openFile.close();    
        }
    }
    if (closedir (iDirectory)) 
    {
        cout<<"Unable to close  "<<itDirectory<<endl;
        exit (1000);
    }
}

}



void walkThroughDirectory(char directory_name[PATH_MAX],char  searchString[PATH_MAX])
{

DIR * directory;
struct dirent * walker;
char d_name[PATH_MAX];
int path_length;
char path[PATH_MAX];
directory=opendir(directory_name);
if(directory==NULL)
{
    cout<<"Error"<<endl;
    cout<<directory_name<<"  Cannot be Opened"<<endl;
    exit(10000);
}
while((walker=readdir(directory)) !=NULL)
{




    strcpy(d_name,walker->d_name);
    cout<<directory_name<<"/"<<endl;
    if (strcmp (d_name, "..") == 0 ||
        strcmp (d_name, ".") == 0) 
    {
        continue;
    }
    else
    {


        path_length = snprintf(path,PATH_MAX,"%s/%s",directory_name,d_name);

        cout<<path<<endl;
        if (path_length >= PATH_MAX) 
        {
            cout<<"Path is too long"<<endl;
            exit (1000);
        }
        if(walker->d_type==DT_DIR)
        {
            pthread_mutex_lock(&mutex);
            saveDirectory.Enqueue(path);
            pthread_mutex_lock(&mutex);
            sem_post(&semaphore1);
            directories++;
            walkThroughDirectory (path,searchString);
        }
        else if(walker->d_type==DT_REG)
        {   
            ifstream openFile;
            openFile.open(path);
            char line[1500];
            int currentLine = 0;
            if (openFile.is_open()) {
                while (openFile.good()) {
                    currentLine++;
                    openFile.getline(line, 1500);
                    if (strstr(line, searchString) != NULL)
                        cout<<path<<": "<<currentLine<<": "<<line<<endl;
                }
            }
            openFile.close();    
        }


    }

}

if (closedir (directory)) 
{
    cout<<"Unable to close  "<<directory_name<<endl;
    exit (1000);
}
}













int main(int argc,char *argv[])
{
char * name;

cout<<"Total Directories  "<< directories<<endl;



name=get_current_dir_name();
cout<<"Current Directory is:  "<<name<<endl;
sem_init(&semaphore1,0,0);
strcpy(searchStringThread,argv[1]);
int number_of_threads=atoi(argv[3]);
pthread_t threads[number_of_threads];




walkThroughDirectory(argv[2],argv[1]);
pthread_mutex_lock(&mutex);
saveDirectory.Enqueue(argv[2]);
pthread_mutex_unlock(&mutex);
sem_post(&semaphore1);

for(int i=0;i<number_of_threads;i++)
{
    pthread_create(&threads[i],NULL,threadHandler,NULL);
}
for(int j=0;j<number_of_threads;j++)
{
    pthread_join(threads[j],NULL);
}
while(saveDirectory.isEmpty())
{
    cout<<"Queue is Empty"<<endl;
    cout<<"Exiting"<<endl;
    exit(10000);
}
free(name);
cout<<"Total Directories  "<< directories<<endl;


return 0;
}
4

1 に答える 1

2

完了時にミューテックスをロック解除するのではなく、2 回ロックする単純なバグがあります。

        pthread_mutex_lock(&mutex);
        saveDirectory.Enqueue(path);
        pthread_mutex_lock(&mutex);

次のようにする必要があります。

        pthread_mutex_lock(&mutex);
        saveDirectory.Enqueue(path);
        pthread_mutex_unlock(&mutex);

注: これは、他に問題がないということではありません。これは、おそらく差し迫った問題であるということです。

最大の問題は、ディレクトリをキューに置いたように見えることですsaveDirectory(そのため、別のスレッドがそれをプルして作業することができます)。次に、そのディレクトリをキューに置いたスレッドで再帰的にプロセスを進めます。作業をスレッド間でどのように分割するかについて、もう少し考える必要があると思います。

さらにいくつかのマイナーなコメント:

  • std::string許可されている場合は、使用を検討してください。文字列処理の一部をより簡単にする必要があります( directoryQueue::Dequeue()たとえば、から返されたデータからメモリをリークします)
  • クラスが存在する主な理由が directoryQueue複数のスレッドの作業項目を保持することである場合、呼び出し元がその複雑さに対処する必要がないように、独自のミューテックスを管理する必要があるかもしれません
于 2012-04-25T19:11:30.060 に答える