/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
[VC++] bruge Class member function i Threa~
Fra : Kim Schulz


Dato : 15-11-04 16:14

jeg sidder med et projekt i Visual C++ (studio .NET) hvor jeg har behov
for at en tråd kan bruge nogle data i en klasse jeg har.
jeg ville egenligt have lavet det sådan at tråden kørte på en
DWORD WINAPI ThreadFunC(LPVOID in)
som jeg har i min class men jeg opdagede så at CreateThread ikke kan
håndtere at få en member-function ind til at udføre.

Hvad pokker gør man så?

Jeg kan selvfølgelig gøre metoden global (ude af klassen) men så har den
ikke adgang til de private ting inde i klassen.

nogen forslag?

--
Kim Schulz | Linux - Your Choice! Your Opinion! Your life!
Geek by nature |
schulz.dk |

 
 
Jakob Nielsen (15-11-2004)
Kommentar
Fra : Jakob Nielsen


Dato : 15-11-04 16:34

>jeg sidder med et projekt i Visual C++ (studio .NET) hvor jeg har behov
>for at en tråd kan bruge nogle data i en klasse jeg har.
>jeg ville egenligt have lavet det sådan at tråden kørte på en
>DWORD WINAPI ThreadFunC(LPVOID in)
>som jeg har i min class men jeg opdagede så at CreateThread ikke kan
>håndtere at få en member-function ind til at udføre.

>Jeg kan selvfølgelig gøre metoden global (ude af klassen) men så har den
>ikke adgang til de private ting inde i klassen.

Hvad med at gøre metoden static? Det er samme slags funktionspointere der
anvendes dertil.
Hvis du kan give din metode en pointer til det objekt du faktisk arbejder
med, så kan det gå den vej omkring?



Kim Schulz (15-11-2004)
Kommentar
Fra : Kim Schulz


Dato : 15-11-04 16:36

[snip]
> Hvad med at gøre metoden static? Det er samme slags
funktionspointere
> der anvendes dertil.

ikke muligt da metoden kalder non-static metoder.

> Hvis du kan give din metode en pointer til det objekt du faktisk
> arbejder med, så kan det gå den vej omkring?

Det forsøger jeg lige nu. er det egenligt muligt at smide mere end en
parameter med til tråde metoden?


--
Kim Schulz | Keen of Fundanemt? Want to share experieces with
Geek by nature | other users? join The Fundanemt User Group NOW!
schulz.dk | http://www.fundausers.org

Mogens Hansen (15-11-2004)
Kommentar
Fra : Mogens Hansen


Dato : 15-11-04 18:40


"Kim Schulz" <kim@schulz.dk> wrote in message
news:20041115161423.43674e68@lifesuckz.nork.auc.dk...

[8<8<8<]
> Hvad pokker gør man så?

Den simpleste måde er at lave en lille hjælpe-funktion, som kalder
member-funktionen.
Pointeren til objektet sendes til "CreateThread" som "lpParameter".

Altså:

class foo
{
// ...
void func();
// ...
};

DWORD WINAPI foo_func_thunk(LPVOID lpParameter)
{
reinterpret_cast<foo*>(lpParameter)->func();
return someResult;
}

void bar(foo& obj)
{
// ...

DWORD threadId;
CreateThread(threadAttributes, stackSize, foo_func_thunk, &obj,
creationFlags, &);

// ...
}

Der findes en mere avancerede måde, hvor call-thunken bliver lave dynamisk
på runtime - men det kan typisk ikke svare sig.


Venlig hilsen

Mogens Hansen



Klaus Petersen (15-11-2004)
Kommentar
Fra : Klaus Petersen


Dato : 15-11-04 19:27

> Der findes en mere avancerede måde, hvor call-thunken bliver lave dynamisk
> på runtime - men det kan typisk ikke svare sig.

Kender du metoden? Den kunne jeg godt tænke mig at høre mere om.



Mogens Hansen (15-11-2004)
Kommentar
Fra : Mogens Hansen


Dato : 15-11-04 22:22


"Klaus Petersen" <ng@spectual.ra.bnaa.dk> wrote in message
news:4198f4e8$0$33740$14726298@news.sunsite.dk...
>> Der findes en mere avancerede måde, hvor call-thunken bliver lave
>> dynamisk
>> på runtime - men det kan typisk ikke svare sig.
>
> Kender du metoden?

Ja.
Den er dog mere relevant i forbindelse på steder hvor der ikke kan føre en
void pointer med, og hvor man ofte skal lave en mapning fra en funktion til
et objekt.

Det er f.eks. anvendt i flere biblioteker hvor man har lavet en
objekt-orienteret indpakning af vinduer til MS-Windows (bl.a. Borland OWL og
Microsoft WTL).
Her vil man sende en Window message til et objekt - gerne i konstant, kort
tid.

> Den kunne jeg godt tænke mig at høre mere om.

Man allokerer et stykke hukommelse, som man fylder med passende op-koder
(assembler instruktioner) og gemmer passende ekstra information sammen med
koden.
Den funktion (f.eks. CreateThread) som kræver adressen på en call-back
metode får så bare en adresse til det netop allokerede og initialiserede
hukommelse.
Altså man laver simpelt hen en funktion pr. objekt på runtime

Nedenstående er noget kode jeg har skrevet for en del år siden, der kunne
mappe fra WNDPROC til et "Window" objekt.
Det er ikke let læseligt - men effektivt

// This structure _must_ be packed
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
#pragma option push -a1
#elif defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 700 == __INTEL_COMPILER) && defined(_WIN32)
// Intel C++ for Windows V5.0, V6.0 or V7.x
#pragma pack(push, 1)
#elif defined(_MSC_VER)
// Microsoft Visual C++V7.1 (.NET 2003)
#pragma pack(push, 1)
#endif

class InstanceThunk
{
public:
InstanceThunk(Window* wnd, WNDPROC wndproc)
{
call = 0xE8u; // CALL rel32
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
offset = offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#elif (defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 600 == __INTEL_COMPILER) && defined(_WIN32)) ||
defined(__COMO__)
// Intel C++ for Windows V5.0, V6.0 or V7.1
// Comeau C++ for Windows
// offsetof is not supported by Intel C++
offset = 8; //offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#elif (defined(_MSC_VER))
// Microsoft Visual C++ 7.1 (.NET 2003)
offset = 8; //offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#endif
proc = wndproc;
window = wnd;
// POP ECX
//
// Pop return address of call into ecx (address of member "proc")
//
code[0] = 0x59u;

// MOV EDX, [ECX+4]
//
// load "window" into edx
//
code[1] = 0x8B;
code[2] = 0x51u;
code[3] = 0x04u;

// JMP [ECX]
//
// jump to window function provided
code[4] = 0xFFu;
code[5] = 0x21u;
}

WNDPROC WndProc()
{
return reinterpret_cast<WNDPROC>(this);
}

private:
unsigned char call;
int offset;
WNDPROC proc;
Window* window;
unsigned char code[6];

private:
InstanceThunk(const InstanceThunk&);
InstanceThunk& operator=(const InstanceThunk&);
};
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
#pragma option pop
#elif defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 700 == __INTEL_COMPILER) && defined(_WIN32)
// Intel C++ for Windows V5.0, V6.0 og V7.x
#pragma pack(pop)
#elif defined(_MSC_VER)
// Microsoft Visual C++V7.1 (.NET 2003)
#pragma pack(pop)
#endif



Venlig hilsen

Mogens Hansen



Klaus Petersen (16-11-2004)
Kommentar
Fra : Klaus Petersen


Dato : 16-11-04 00:25

[snip]

hmm... interessant. Men det er vel noget compiler/linker specifikt kode?



Mogens Hansen (16-11-2004)
Kommentar
Fra : Mogens Hansen


Dato : 16-11-04 20:12


"Klaus Petersen" <ng@spectual.ra.bnaa.dk> wrote in message
news:419a3818$0$33731$14726298@news.sunsite.dk...
> [snip]
>
> hmm... interessant. Men det er vel noget compiler/linker specifikt kode?

Ja - bestemt. Og CPU arkitektur specifikt.
I koden er der også en test, der sikrer at det ikke umiddelbart oversætter
på nye compilere. På den måde husker man at teste det grundigt.

Venlig hilsen

Mogens Hansen



Kim Schulz (15-11-2004)
Kommentar
Fra : Kim Schulz


Dato : 15-11-04 19:08

[snip]
> Du snakker .net og alt lyder som om det er win32, så jeg ved
ikke helt
> hvad det egentlig er du bruger..?

eneste jeg har nævnt med .NET er version af mit udviklingsmiljø. Jeg
prøver så vidt muligt at holde mig fra .NET.


>En thread tager dog normalt en 32

> bit størelse som ekstre (somme tider ligegyldigt) argument. Dette kan
> være en pointer til hvad som helst. Eventuelt en struct med vilkårligt
> mange argumenter i.

Det er også den løsning som jeg bruger nu. Kunne jo bare godt være der
var en pæn løsning.

--
Kim Schulz | Fundanemt Content Management system:
Geek by nature | http://www.fundanemt.com
schulz.dk | http://www.fundusers.org

Kim Schulz (16-11-2004)
Kommentar
Fra : Kim Schulz


Dato : 16-11-04 09:44

[snip]

Det her virker rigtigt godt, men så kom det næste problem til syne.
Når jeg inde fra min tråd forsøger at connecte til en NamedPipe, så
afslutter programmet bare pludselig med exitcode 0

koden hvor det sker ser således ud:

subscribePipe = CreateNamedPipe(
      subscribePipeName, // Name of the Pipe
      PIPE_ACCESS_INBOUND, // Server reads, client writes
      PIPE_READMODE_BYTE | // Read data as a stream of bytes
      PIPE_WAIT, // Enable blocking mode
      1, // Only a single instance
      BUFFER_SIZE, // Output buffer size
      BUFFER_SIZE, // Input buffer size
      NMPWAIT_WAIT_FOREVER, // Timeout used for WaitNamedPipe
      NULL // Default security attributes
      );
if (subscribePipe == INVALID_HANDLE_VALUE) {
   return false;
}
result = ConnectNamedPipe(subscribePipe, NULL) ?
      TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


i sidste linje dør den bare. Jeg har debugget programmet og steppet into
i den linje men den når aldrig længere ind, inden den dør.

Nogen der har en ide til hvorfor dette kan ske?

subscribePipe er forresten et HANDLE og result er BOOL. Begge er
defineret inde i samme scope som de viste linjer.



--
Kim Schulz | Need a Content Management System for your website? Go
Geek by nature | get Fundanemt at : http://www.fundanemt.com New
schulz.dk | version out now!

Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408914
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste