Avatar billede ppdk Nybegynder
20. februar 2005 - 20:02 Der er 13 kommentarer

Threads og class som parameter

Jeg har en thread, hvor jeg gerne vil parse en class som parameter til..

Min kode ligner noget lignende (små udklip fra forskellige filer):

// Et namespace; Dto
class ChannelDto
{
public:
  SOCKET * ChannelSocket;
  int Type;
  int Port;
};


// Et namespace SocketFunctions
DWORD WINAPI SocketFunctions::DataChannelThread(LPVOID lp)
{
  Dto::ChannelDto channelDto = (Dto::ChannelDto)&lp;
  while (true) { Sleep(1000); printf("ChannelType: %i", channelDto.Type); }
}

// Main-funktion
// SocketFunctions::DataChannelSocket er af typen SOCKET
Dto::ChannelDto DataChannel;
DataChannel.ChannelSocket = &SocketFunctions::DataChannelSocket;
DataChannel.Type = 1;
DataChannel.Port = 8000;
SocketFunctions::DataChannelThreadHandle = CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, &DataChannel, NULL, NULL);


Mit problem opstår i min funktion der kører thread'en, SocketFunctions::DataChannelThread - den kører fint, men den vil ikke lade mig caste typen;
Dto::ChannelDto channelDto = (Dto::ChannelDto)&lp;

What to do?
Avatar billede bertelbrander Novice
20. februar 2005 - 20:06 #1
Man kan ikke bruge en almindelig funktion i en class til som thread funktion, kun static  member funktioner.

En måde at omgå problemet:
http://home20.inet.tele.dk/midgaard/snip/thread2.html
Avatar billede ppdk Nybegynder
20. februar 2005 - 20:18 #2
Det er ikke en class, det er et namespace, derfor kan jeg godt bruge funktionen som en thread...
Avatar billede ppdk Nybegynder
20. februar 2005 - 20:20 #3
Threaden i sig selv kører fint - det har jeg testet - problemet opstår når jeg prøver at parse ChannelDto-klassen som en parameter til threaden, og skal type-caste den i threaden.
Avatar billede bertelbrander Novice
20. februar 2005 - 20:56 #4
Har du prøvet med:
Dto::ChannelDto *channelDto = (Dto::ChannelDto *)lp;

Så vidt jeg kan se giver du CreateThread en pointer til en DataChannel.
Avatar billede bertelbrander Novice
20. februar 2005 - 21:02 #5
Dette ser ud til at virke:
#include <windows.h>
#include <string>
#include <iostream>

namespace Dto
{
class ChannelDto
{
public:
  std::string S;
};
}

namespace SocketFunctions
{
DWORD WINAPI DataChannelThread(LPVOID lp);
DWORD WINAPI SocketFunctions::DataChannelThread(LPVOID lp)
{
  Dto::ChannelDto *channelDto = (Dto::ChannelDto *)lp;
  std::cout << channelDto->S << std::endl;
  return 0;
}
}

int main()
{
  Dto::ChannelDto DataChannel;
  DataChannel.S = "Hello World";
  CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, &DataChannel, NULL, NULL);
  Sleep(1000);

}
Avatar billede ppdk Nybegynder
20. februar 2005 - 21:27 #6
Hallo - nu virker det jo :)

Men når jeg forsøger i min thread at lave f.eks. følgende:

DWORD WINAPI SocketFunctions::DataChannelThread(LPVOID lp)
{
  Dto::ChannelDto *channelDto = (Dto::ChannelDto *)lp;
  while (true) { Sleep(10000); printf("ChannelType: %i\n", channelDto->Type); }
}

Som sættes sådan:

Dto::ChannelDto DataChannel;
DataChannel.ChannelSocket = &SocketFunctions::DataChannelSocket;
DataChannel.Type = 1;
DataChannel.Port = 8000;
SocketFunctions::DataChannelThreadHandle = CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, &DataChannel, NULL, NULL);

Så får jeg nogle mærkelige output - kæmpe negative og positive tal - og ihvertfald ikke det Type = 1; som jeg satte ved start
Avatar billede ppdk Nybegynder
20. februar 2005 - 22:31 #7
Kan det have noget at gøre med, at jeg skal have en pointer-til-pointer defination, altså noget a'la Dto::ChannelDto **channelDto = (Dto::ChannelDto **)lp; ?

Men det kan den ikke lide - det brokker den sig over..
Avatar billede bertelbrander Novice
20. februar 2005 - 23:54 #8
Det kan være fordi det object du giver med til CreateThread ophører med at eksistere inden du får du udskrevet. Jeg kan ikke se nok context til at vide om det er det der sker.

Prøv at new'e DataChannel og delete det i tråden.
Avatar billede ppdk Nybegynder
21. februar 2005 - 00:02 #9
Jeg er ikke helt med - hvad skulle det kunne vise? :)
Avatar billede ppdk Nybegynder
21. februar 2005 - 00:07 #10
Tror muligvis jeg har set problem, ud fra din kommentar - mit objekt bliver lavet sådan;

bool SocketFunctions::ServerStart(int DataChannelPort, int StreamAPort, int StreamBPort)
{
  Dto::ChannelDto DataChannel;
 
  DataChannel.ChannelSocket = &SocketFunctions::DataChannelSocket;
  DataChannel.Type = 1;
  DataChannel.Port = DataChannelPort;
  SocketFunctions::DataChannelThreadHandle = CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, (LPVOID)&DataChannel, NULL, NULL);

  if (SocketFunctions::DataChannelThreadHandle == NULL)
    return false;
  else
    return true;
}

Det er vel ikke så underligt at det bliver nedlagt, når det lokale objekt forsvinder når funktionen ophører - men er det er jo ikke muligt at parse en klasse direkte til en thread, da parameteren er defineret som "void *" - så der er vel ikke andet for end af deklarere Dto'en som et globalt objekt?
Avatar billede bertelbrander Novice
21. februar 2005 - 00:08 #11
Hvis jeg ændrer mit program til:
DWORD WINAPI SocketFunctions::DataChannelThread(LPVOID lp)
{
  Dto::ChannelDto *channelDto = (Dto::ChannelDto *)lp;
  Sleep(100);
  std::cout << channelDto->S << std::endl;
  return 0;
}
}

int main()
{
  {
      Dto::ChannelDto DataChannel;
      DataChannel.S = "Hello World";
      CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, &DataChannel, NULL, NULL);
  }
  Sleep(1000);
}

Går det galt, fordi main nedlægger DataChannel objektet inden tråden får den udskrevet.

Men dette virker:

DWORD WINAPI SocketFunctions::DataChannelThread(LPVOID lp)
{
  Dto::ChannelDto *channelDto = (Dto::ChannelDto *)lp;
  Sleep(100);
  std::cout << channelDto->S << std::endl;
  delete channelDto;
  return 0;
}
}

int main()
{
  {
      Dto::ChannelDto *DataChannel = new Dto::ChannelDto;
      DataChannel->S = "Hello World";
      CreateThread(NULL, NULL, SocketFunctions::DataChannelThread, DataChannel, NULL, NULL);
  }
  Sleep(1000);
}
Avatar billede ppdk Nybegynder
21. februar 2005 - 00:35 #12
Fik løst problemet ved at deklarere det som extern Dto::ChannelDto ChannelData under SocketFunctions - så den metode må jeg leve med - smid et svar, så er der points
Avatar billede bertelbrander Novice
21. februar 2005 - 00:44 #13
Som jeg viste kan du løse det ved at bruge new og delete. Metoden med en global/static kan naturlig vis også virke, i det mindste indtil du får brug for at have to tråde på samme tid ...

Jeg samler ikke på point.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester