0

我正在尝试实现一个线程池,并且在获取我应该使用的文件路径以比它们存在于 ftw 的 OnOpen 函数中的临时实例更永久地存储时遇到了很多麻烦. 我不允许对每个处理的文件路径执行 malloc。

这是我目前必须尝试让 OnOpen 不向我的线程提供临时数据的方法,我对它在 memcpy 上崩溃的原因感到困惑。

我很想知道如何在不创建多余的 char* 数组的情况下从正在编辑的临时变量中获取数据以确保数据安全,而我使用它来执行 memcpy。

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 *)字节,而不是整个字符串。
    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 回答