2011-01-13 5 views
1

複数のスレッドデータにアクセスして変更する際に問題があります。これを行う適切な方法はありますか?ここでC++のスレッドデータの問題へのアクセスと変更

は私の完全なコードです:

#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' 値が同じです。文字列の値を変更するにはどうすればよいですか?

+0

サイドコメント。ポインタの算術演算を手動で処理するのではなく、間違ってしまうのは簡単です。パラメータを 'threadfn'の既知の型にキャストするだけです:' data * param = static_cast (lpParam); /*...*/param-> a = 200; param-> b = 25.80; ' –

答えて

6

あなたは何をやっているのですか? lpDataのキャストはすべて非常に間違っています。あなたが何かを達成するために多くのキャスティングをしなければならないなら、あなたはおそらくそれを正しい方法でやっていないでしょう。

とにかく、あなたのコードは次のようになります。それは基本的にあなたがCreateThreadを呼び出したときに何が起こっているか逆転しているためあなたが(data *)(lpParam)を使用する必要があります

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; 
} 

。個人的には、実際に何が起こっているのかを隠すので、タイプ名の表記は援助よりも邪魔になります。PHungarian notationは一般にこの問題を抱えています。あなたのmain機能で

、あなたはこのコードを持っている:

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

CreateThreadに第四引数は(PVOID別名)void *です。式&threadのタイプはdata *です。これは、data *が暗黙的にvoid *に変換されていることを意味します。あなたはその変換を明示的に作成した場合、コードは次のようになります。だから、

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

、行われていたものを「元に戻す」ために、あなたは「逆」キャストする必要があります。 void *data *に戻す必要があります。つまり、threadfnにはdata *lpData = (data *)(lpParam);というコードが必要です。

さらに、const char *として宣言していないため、cを定数文字列に設定することで災害に遭っています。私はコンパイラがあなたにエラーを与えていないことに驚いています。災害は、data.c[0] = 'f';のようなことをすると起こります。これを行うと、読み取り専用としてフラグが立てられている可能性のあるメモリを変更しようとし、プログラムがクラッシュする可能性があります。そして、それは起こり得る最も親切なものです。

+0

ありがとう!私はこの方法を見てきましたが、エラーが続いています。 –

+0

@Chicko Bueno - あなたがキャストしたキャスト(別名 'data * lpData =(data *)(lpParam);)が正しいのですか? – Omnifarious

+0

'for'ループは正しいか意図していますか? –

0

ポインタ演算がオフです。

cは構造体のオフセット8にあります。しかし

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

あなたはchar *にlpParamをキャスト。 Charのサイズは1バイト(Windowsでは少なくとも)です。ポインタに2を加えて、構造体の2バイトをオフセットするように書きます。

lpParamをfloat *にキャストしているため、あなたの他のポインタの算術演算は、(float *)lpParam + 1が構造体のオフセット4に書き込むことを意味します。

Omnifariusが示唆したように、lpParamをスレッドデータ構造体へのポインタにキャストし、それを介してメンバーにアクセスするだけです。

2

スポーンされたスレッド内から構造メンバーに正しくアクセスしていません。

*(int*)lpParam = 200; 

これは、lpParamをint *に変換し、そのアドレスの整数にアクセスすることを意味します。それが正常に動作しますが、:

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

がfloat *にlpParamを変換し、その後、それを間接参照し、それにバイト(フロート*)はsizeofを追加します。これは、sizeof(int)がsizeof(float)と同じになる場合にのみ有効です。これは一般的には十分ですが保証されていません。

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

これはしかし本当の心配である:これはlpParamのchar *を考慮し、次に半分は(32を想定構造体の整数メンバーによって使用される4つのバイトにおそらくそれを位置決めおり、これに2つのバイトを追加charポインタから切り捨てられた値(最下位バイト/ char)を新しい文字列[Chrisのコメントのおかげで組み込む]でそのアドレスの1文字を上書きします。

代わり:ここ

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

基本的なポイントは、スレッド関数がvoid *引数を取るので、あなたは型情報を失うということです。スレッドが実行を開始したときに最初にやりたいことは、その型情報を復元することで、コンパイラは自分が行っていることが安全で賢明であることを確認できます。

+0

あなたの答えは私の答えに大きな助けとなります。 :-) – Omnifarious

+0

@Omnifarious:ええ - うまく一緒に働く - あなたはそれを解決して(そしてchar *の問題に気づいた)、もっと詳しく説明しました(^_^) –

+0

"その後、あなたの新しい文字列へのcharポインタを持つfloatメンバの一部。 " - いいえ、その割り当てはcharにすぎず、1バイトしか書きません。この場合、intの3番目の最下位バイト。注:740578 == 0x007100B2 == 0x00710000 + 200. –

関連する問題