0

私はスレッドプールを実装しようとしています.ftwのOnOpen関数内に存在する一時的なインスタンスよりも永続的に保存されるように、作業するはずのファイルパスを取得するのにかなりの問題があります. . 処理されるすべてのファイルパスに対して malloc を実行することは許可されていません。

これは現在、OnOpen がスレッドに一時データを渡さないようにしようとしているものであり、memcpy でクラッシュする理由について混乱しています。

memcpy を実行する char* の余分な配列を作成せずに、編集中の一時変数からデータを保護する方法を知りたいです。

typedef struct Task{
    void (*taskFunc)(char*);
    char* arg;
} Task;

void HashFunc(char* arg)
{
    pthread_mutex_lock(&lock);
    printf("%s\n", arg);
    thingsDone++;
    pthread_mutex_unlock(&lock);
}

static int OnOpen(const char* path, const struct stat* sb, int flags)//will send folder paths too
{
    if(strstr(path, ".exe") || strstr(path, ".cfg")) return 0;
    Task t = {
        .taskFunc = &HashFunc,
        .arg = path
    };
    memcpy(t.arg, path, strlen(path));
    while(taskCount == MAX_OPEN_FILE_HANDLES-1); //busy wait
    submitTask(t);
    return 0;
}

編集:素晴らしいフィードバックですが、それは私が必要としているものではありません.

以下に、私が問題を抱えているコード、つまりスレッドプールとタスク構造体の使用方法に関連するものをいくつか追加します。それについて行くことができます:

void executeTask(Task* task) {task->taskFunc(task->arg);}

void* threadFunc(void* arg)
{
    Task task;
    while (!(doneSending==1 && thingsDone == thingsToDo))
    {
        pthread_mutex_lock(&lock);
        while (taskCount==0 && doneSending==0) {pthread_cond_wait(&condQueue, &lock);}
        task = taskQueue[0];
        for (int i = 0; i < taskCount-1; i++) {taskQueue[i] = taskQueue[i+1];}
        taskCount > 0 ? --taskCount : 0;
        pthread_mutex_unlock(&lock);
        if (doneSending==0 || thingsDone<thingsToDo) executeTask(&task);
        printf("%d, %d, %d, %d\n", taskCount, thingsDone, thingsToDo, doneSending);
    }
}

void submitTask(Task task)
{
    pthread_mutex_lock(&lock);
    taskQueue[taskCount++] = task;
    ++thingsToDo;
    pthread_mutex_unlock(&lock);
    pthread_cond_signal(&condQueue);
}

私のスレッドプールは 8 つのスレッドで構成されており、これは私の taskQueue のサイズでもあります。

以前は持って.arg = strcpy(temp, path)いましたが、temp は一時的であるため、hashFunc に不正なデータが出力されました。

各スレッドは、互いに干渉する危険を冒さないように、動作する Task 構造体の独自のコピーを持つことになっています。


最終編集:私はそれを機能させました。これがどのように見える必要があるかです:

volatile int taskIdx = 0, pathIdx = 0;

Task taskArray[MAX_OPEN_FILE_HANDLES];
char* pathQueue[MAX_OPEN_FILE_HANDLES];

void* threadFunc(void* args)
{
    Task task;
    while (!(doneSending==1 && taskIdx == pathIdx))
    {
        if (doneSending && taskIdx==pathIdx) break;
        pthread_mutex_lock(&lock);
        pthread_cond_wait(&condArray, &lock);
        if (doneSending && taskIdx==pathIdx)
        {
            pthread_mutex_unlock(&lock);
            break;
        }
        task = taskArray[taskIdx];
        taskIdx = (taskIdx+1)%MAX_OPEN_FILE_HANDLES;
        pthread_mutex_unlock(&lock);
        executeTask(&task);
    }
}

void submitTask(Task t)
{
    pthread_mutex_lock(&lock);
    taskArray[pathIdx] = t;
    pathIdx = (pathIdx+1)%MAX_OPEN_FILE_HANDLES;
    pthread_cond_signal(&condArray);
    pthread_mutex_unlock(&lock);
}

static int OnOpen(const char* path, const struct stat* sb, int flags)
{
    if(flags != FTW_F || strstr(path, ".cfg") || strstr(path, ".exe") || strstr(path, ".vscode") || strstr(path, "anticheat") || strstr(path, "Makefile")) return 0;
    if (thingsToDo-thingsDone == MAX_OPEN_FILE_HANDLES) HashFunc((char*)path, thingsToDo++);
    else
    {
        Task t = {
            .taskFunc = &HashFunc,
            .filePath = strcpy(pathQueue[pathIdx], path)
        };
        submitTask(t);
    }
    return 0;
}

int main()
{
    pthread_mutex_init(&lock, NULL);
    pthread_cond_init(&condArray, NULL);
    for (int i=0; i<MAX_OPEN_FILE_HANDLES; i++)
    {
        if(pthread_create(&pool[i], NULL, &threadFunc, NULL) != 0) perror("pth_create");
        pathQueue[i] = calloc(MAX_PATH_LENGTH, sizeof(char));
    }
4

2 に答える 2

1
  1. を保存するためのメモリを割り当てません。path
  2. sizeof(path)の長さではなく、ポインターの長さを示していpathます。文字列の長さを取得するにはstrlen
  3. memcpy(t.arg, path, sizeof(path));sizeof(char *)文字列全体ではなく、number バイトのみをコピーします。
    size_t arglen = strlen(path);
    Task t = {
        .taskFunc = &HashFunc,
        .arg = malloc(arglen + 1),
    };
    
    /* add some error checking */
    strcpy(t.arg, path);
于 2021-09-10T12:20:22.637 に答える
0

初め。

memcpy(t.arg, path, sizeof(path));

この操作は非常に間違っています。sizeof(path)ポインタ変数のサイズを返します。弦の長さとはあまり関係ありません。を使用しstrcpyます。

文字の配列を に入れるだけstruct Taskです。すべてのスレッドは、他のスレッドに干渉することなく独自のコピーを持ちます。

typedef struct Task{
    void (*taskFunc)(char*);
    char arg[PATH_MAX];
} Task;
strcpy(Task.arg, path);

編集

arg各スレッドが(全体ではなく)独自のコピーを持つことが予想される場合は、Task単に使用してstrdup()ください。strlen()/malloc()/strcpy()シーケンスよりもはるかに便利です。

    Task t = {
        .taskFunc = &HashFunc,
        .arg = strdup(path),
    };

free(t.arg)スレッドがジョブを終了したときにメモリを解放することを忘れないでください。

于 2021-09-10T12:17:45.873 に答える