Как мне скопировать эту временную переменную 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.
Раньше, у меня был
Предполагается, что у каждого потока будет своя собственная копия структуры Task, с которой он будет работать, чтобы они не мешали друг другу.
2 ответа
- Вы не выделяете память для хранения
-
sizeof(path)
дает вам длину указателя, а не длинуpath
. Чтобы получить длину строки, используйтеstrlen
-
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)
когда поток завершает свою работу.