Как мне скопировать эту временную переменную char* в мою структуру для более постоянного хранения?

Я пытаюсь реализовать пул потоков, и у меня возникают проблемы с получением путей к файлам, с которыми я должен работать, для более постоянного хранения, чем временный экземпляр, который они существуют внутри функции OnOpen из ftw. Мне не разрешено использовать 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.

Раньше, у меня был но поскольку temp временный, у меня в hashFunc напечатаны неверные данные.

Предполагается, что у каждого потока будет своя собственная копия структуры Task, с которой он будет работать, чтобы они не мешали друг другу.

2 ответа

  1. Вы не выделяете память для хранения
  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);

Первый.

      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) когда поток завершает свою работу.

Другие вопросы по тегам