2011-01-13 3 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; 
} 

. 개인적으로, 바보 같다고 생각하면 형식 이름에 대한 표기법은 실제로 발생하는 것을 가려 내기 때문에 도움이되지 않습니다. 일반적으로 Hungarian notation에이 문제가 있습니다. CreateThread

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

제 4 인수가 void * (일명 PVOID)이다 : 당신의 main 기능에

, 당신은이 코드가 있습니다. 식 &thread의 형식은 data *입니다. 즉 data *이 암시 적으로 void *으로 변환되고 있음을 의미합니다. 당신이 변환을 명시 할 경우, 코드는 다음과 같습니다

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

그래서하기 위해 '취소'일이 있었는지, 당신은에 '반대'캐스트가 필요합니다. void *data *으로 다시 설정해야합니다. 이는 threadfn보다 코드 data *lpData = (data *)(lpParam);이 필요하다는 것을 의미합니다.

또한 cconst char *으로 선언하지 않았으므로 상수 문자열을 가리 키도록 설정하여 재앙을 준비하고 있습니다. 나는 컴파일러가 오류를주지 않는다는 것에 놀랐다. 재해는 data.c[0] = 'f';과 같은 일을 할 때 발생합니다. 그렇게하면 읽기 전용으로 플래그가 지정된 메모리를 수정하려고 시도하고 프로그램이 중단 될 수 있습니다. 그리고 그것은 일어날 수있는 가장 친절한 일입니다.

+0

정말 고마워요! 나는이 방법을 조사했지만 오류가 계속 발생합니다. –

+0

@Chicko Bueno - 내가 한 캐스팅 (일컬어'data * lpData = (data *) (lpParam);)이 올바른 일인 이유를 이해합니까? – Omnifarious

+0

'for' 루프가 정확하고 의도적입니까? –

0

포인터 연산이 꺼져 있습니다.

c는 구조체의 오프셋 8에 있습니다. 그러나

는 :

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

당신은 * 숯불에 lpParam를 캐스팅. Char의 크기는 1 바이트입니다 (Windows의 경우 최소). 포인터에 2를 추가하여 struct에 2 바이트 오프셋을 씁니다.

lpParam을 float *로 캐스팅했기 때문에 다른 포인터 연산이 작동합니다. 즉, (float *) lpParam + 1은 struct에서 4를 오프셋으로 씁니다.

Omnifarius가 제안 했으므로 lpParam을 스레드 데이터 구조에 대한 포인터에 캐스트하고이를 통해 구성원에 액세스하십시오.

2

생성 된 스레드 내에서 구조 멤버에 올바르게 액세스하지 않습니다. 이것을 고려하십시오 :

*(int*)lpParam = 200; 

그것은 그 주소의 정수를 액세스있는 int *로 lpParam 변환을 의미한다. 그것은 잘 작동하지만 :

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

변환 lpParam 플로트 *에, 다음 sizeof 연산자는 (플로트 *) 추가 그것에 바이트, 다음을 역 참조. sizeof (int)가 sizeof (float)와 같은 경우에만 작동합니다 ... 일반적으로 충분하지만 보증되지는 않습니다.

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

이 비록 진짜 걱정된다 (32을이 숯불 *, 그때 아마 구조체의 정수 구성원에 의해 사용되는 4 바이트로 반쯤 위치 결정하는, 거기에 2 바이트를 추가 lpParam을 고려 가정 그런 다음 char 포인터에서 새 문자열로 잘린 값 (최하위 바이트/char)으로 해당 주소의 단일 문자를 작성합니다. [Chris의 주석 덕분에 수정 통합]. 대신

: 여기

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

기본 포인트는 형식 정보를 잃을 수 있도록 스레드 기능, 무효 * 인수를 취하는 것입니다. 스레드가 실행을 시작할 때 가장 먼저 수행 할 작업은 해당 유형 정보를 복원하여 컴파일러에서 수행중인 작업이 안전하고 합리적인 지 확인할 수 있도록하는 것입니다.

+0

귀하의 대답은 제 대답에 큰 도움이됩니다. :-) – Omnifarious

+0

@Omnifarious : 네 - 함께 잘 작동 해 - 해결 했으므로 (숯 * 문제가 있음), 좀 더 설명해 봤습니다. (^_^) –

+0

"그 나머지 부분에 글을 씁니다. 새 문자열에 대한 char 포인터가있는 float 멤버의 일부. " - 아니요. 할당은 char 일 뿐이며, 1 바이트 만 씁니다. 이 경우 int의 세 번째 최하위 바이트입니다. 참고, 740578 == 0x007100B2 == 0x00710000 + 200. –

관련 문제