【问题标题】:Accessing and modifying thread data problem in c++c++中访问和修改线程数据问题
【发布时间】:2011-01-13 06:46:39
【问题描述】:

我无法访问和修改我的多线程数据。有什么合适的方法吗?

这是我的完整代码:

#include <stdio.h>
#include <windows.h>

// Create thread data structure
struct data
{
    int a;
    float b;
    char *c;
};

DWORD WINAPI threadfn(LPVOID lpParam)
{   
    printf("Address of thread data:\n");

    for(int i=0; i<sizeof(lpParam); i++)
        printf("%X\n", (int*)lpParam + i);

    // Print out initial values
    printf("\nInitial values:\n");
    printf("a: %d\n", *((int*)lpParam));
    printf("b: %.2f\n", *((float*)lpParam + 1));
    printf("c: %s\n", *((int*)lpParam + 2));

    // Modify thread data values
    *(int*)lpParam = 200;
    *((float*)lpParam + 1) = 25.80;
    *((char*)lpParam + 2) = "Es la una";

    return 0;
}

int main()
{
    HANDLE hThread;
    data thread;

    // Set initial thread data values
    thread.a = 10;                  // Integer data type
    thread.b = 15.60;               // Float data type
    thread.c = "Que hora es?";      // String data type

    hThread = CreateThread(NULL, 0, threadfn, &thread, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);

    // Print out thread value after modification
    printf("\nAfter thread modifications:\n");
    printf("a: %d\n", thread.a);
    printf("b: %.2f\n", thread.b);
    printf("c: %s\n", thread.c);

    getchar();
    return 0;
}

这是我的输出:

Address of thread data:
28FF20
28FF24
28FF28
28FF2C

Initial values:
a: 10
b: 15.60
c: Que hora es?

After thread modifications:
a: 7405768
b: 25.80
c: Que hora es?

如您所见,'c' 值是相同的。如何修改字符串值?

【问题讨论】:

  • 旁注。与其手动处理容易出错的指针运算,不如将参数转换为threadfn中的已知类型:data * param = static_cast&lt;data*&gt;(lpParam); /*...*/ param-&gt;a = 200; param-&gt;b = 25.80;

标签: c++ windows multithreading


【解决方案1】:

你到底在做什么?! lpData 的所有转换都是非常非常错误的。如果你必须做这么多的演员来完成某件事,那么你可能做得不对。

不管怎样,你的代码应该是这样的:

DWORD WINAPI threadfn(LPVOID lpParam)
{   
    printf("Address of thread data:\n");

    data *lpData = (data *)(lpParam);

    for(int i=0; i<sizeof(lpParam); i++)
        printf("%X\n", (int*)lpParam + i);

    // Print out initial values
    printf("\nInitial values:\n");
    printf("a: %d\n", lpData->a);
    printf("b: %.2f\n", lpData->b);
    printf("c: %s\n", lpData->c);

    // Modify thread data values
    lpData->a = 200;
    lpData->b = 25.80;
    lpData->c = "Es la una";

    return 0;
}

您应该使用(data *)(lpParam),因为它基本上与您调用CreateThread 时发生的情况相反。就个人而言,认为类型名称的愚蠢P 表示法与其说是帮助,不如说是阻碍,因为它掩盖了实际发生的事情。 Hungarian notation 一般都有这个问题恕我直言。

在您的 main 函数中,您有以下代码:

hThread = CreateThread(NULL, 0, threadfn, &thread, 0, NULL);

CreateThread 的第四个参数是void *(又名PVOID)。表达式&amp;thread 的类型是data *。这意味着data * 被隐式转换为void *。如果你显式地进行转换,代码如下所示:

hThread = CreateThread(NULL, 0, threadfn, (void *)(&thread), 0, NULL);

因此,为了“撤消”已完成的操作,您需要“反转”演员表。您需要将void * 转回data *,这意味着比threadfn 需要代码data *lpData = (data *)(lpParam);

此外,您将c 设置为指向常量字符串,因为您没有将其声明为const char *,因此您正在招致灾难。我很惊讶编译器没有给你一个错误。当您执行data.c[0] = 'f'; 之类的操作时,灾难就会发生。当您这样做时,您将尝试修改很可能被标记为只读并导致程序崩溃的内存。这是可能发生的最善良的事情。

【讨论】:

  • 非常感谢!我一直在研究这种方法,但一直出错。
  • @Chicko Bueno - 你明白为什么我的演员阵容(又名data *lpData = (data *)(lpParam);)是正确的吗?
  • 您能用人类语言的形式向我解释一下“(data *)(lpParam)”吗?非常感谢。
  • @Chicko Bueno - 我在答案中添加了我的解释。
【解决方案2】:

您没有从生成的线程中正确访问您的结构成员。考虑一下:

*(int*)lpParam = 200;

这意味着将 lpParam 转换为 int*,然后访问该地址处的整数。这很好用,但是:

*((float*)lpParam + 1) = 25.80;

将 lpParam 转换为 float*,然后将 sizeof(float*) 字节添加到它,然后取消引用它。仅当 sizeof(int) 恰好与 sizeof(float) 相同时才有效...这很常见但不能保证。

 *((char*)lpParam + 2) = "Es la una";

这是一个真正的担忧:这将 lpParam 视为一个 char*,然后向其添加两个 BYTES,这可能会将其定位到结构的整数成员使用的四个字节的一半(假设是 32 位应用程序),然后用从 char 指针到新字符串的截断值(最低有效字节/字符)覆盖该地址处的单个字符[由于 Chris 的评论而包含更正]。

改为:

data* p = (data*)lpParam;
p->a = ...;
p->b = ...;
p->c = ...;

这里的基本点是线程函数接受一个 void* 参数,所以你会丢失类型信息。当你的线程开始运行时,你要做的第一件事就是恢复该类型信息,以便编译器可以检查你正在做的事情是否安全且合理。

【讨论】:

  • 您的回答对我的回答起到了很好的补充作用。 :-)
  • @Omnifarious:是的 - 一起工作 - 你已经解决了它(并注意到 char* 问题),我已经解释了更多(^_^)
  • "然后用指向新字符串的 char 指针覆盖该 int 的其余部分和 float 成员的一部分。" -- 不,这个赋值只是一个字符,它只写一个字节。在这种情况下,int 的第三个最低有效字节。注意,740578 == 0x007100B2 == 0x00710000 + 200。
【解决方案3】:

您的指针算法已关闭。

c 在结构体中的偏移量 8 处。

但是:

 *((char*)lpParam + 2) = "Es la una";

您将 lpParam 转换为 char*。 Char 的大小为 1 个字节(至少在 Windows 上)。您将两个添加到指针中,因此您正在写入偏移 2 个字节的结构。

由于您将 lpParam 转换为 float*,因此您的其他指针算术恰好起作用,这意味着 (float*)lpParam + 1 写入结构中的偏移量 4。

正如 Omnifarius 建议的那样,只需将 lpParam 转换为指向线程数据结构的指针并通过它访问成员。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多