如何将此临时 char* 变量复制到我的结构中以进行更永久的存储?

Posted

技术标签:

【中文标题】如何将此临时 char* 变量复制到我的结构中以进行更永久的存储?【英文标题】:How do I copy this temporary char* variable into my struct for more permanent storage? 【发布时间】:2021-11-06 22:27:24 【问题描述】:

我正在尝试实现一个线程池,但在让我应该使用的文件路径比它们存在于 OnOpen 中的临时实例更永久地存储时遇到了很多麻烦来自ftw的功能。我不允许对每个处理的文件路径执行 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));
    

【问题讨论】:

您需要先为arg 指针分配内存,然后才能将memcpy 分配给它。 @500-InternalServerError 嗯...是的和否。 memcpy 不可使用 struct stat* sb 定义在哪里? t.arg 是一个指针。你认为它指向什么? 【参考方案1】:

首先。

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) 释放内存。

【讨论】:

嗯...这并不是完全错误,但是...考虑一下memcpy 即使在此修复之后也能正常工作? @4386427 这取决于哪些数据应该在每个线程中持久化,Task 还是路径?【参考方案2】:
    您没有分配任何内存来存储path 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);

【讨论】:

以上是关于如何将此临时 char* 变量复制到我的结构中以进行更永久的存储?的主要内容,如果未能解决你的问题,请参考以下文章

来自Settings.settings变量的WPF触发器

在火花分析之前从 FTP 读取大文本文件

关于复制struct的Segfault

Revit C#:将现有按钮复制到我的功能区

将第三方 dll 链接到我的 dll

如何将此程序集加载到我的 AppDomain 中?