std::thread - Struktura jako parametr funkcji

0

Witam
Zgodnie z radą, żeby zamiast używać _beginthread oraz castowania na void* zacząłem używać std::thread.
Większość funkcji działa tak jak powinna, jednak w momencie próby stworzenia wątku z funkcji, która jako parametr zawiera strukturę pojawia się poniższy błąd oraz otwiera plik Microsoft Visual Studio 2012\VC\crt\src\intel\chkstk.asm.
Unhandled exception at 0x00CB0677 in Projekt na konkurs Interaktywny produkt IT.exe: 0xC00000FD: Stack overflow (parameters: 0x00000000, 0x002E2000).

Ten kod działa poprawnie:

#include <array>
#include <thread>
...

const short int w = 100;
const short int h = 200;

struct Coord{

	short int CX;
	short int CZ;
	short int X;
	short int Y;
	short int Z;

};

struct WWR{

	short int X;
	short int Y;
	short int Z;
	short int R;
	short int K;
	short int Power;

};

struct WySK{

	short int Beg;

	short int Large;
	double P;
	
	bool NewBlock;

	Coord End;

};

struct WWL{

	short int X;
	short int Y;
	short int Z;
	short int R;
	short int Power;

	double C;

	WySK LPr;

};

struct Chunk{

	short int epolx;
	short int epolz;

	bool Rd;

	std::array <std::array <std::array <short int, w>, h>, w> ty;
	std::array <std::array <std::array <short int, w>, h>, w> tK;
	std::array <std::array <std::array <short int, w>, h>, w> tS;
	std::array <std::array <std::array <short int, w>, h>, w> tR;
	std::array <std::array <std::array <short int, 2>, h>, w> Map;

	std::vector <WWR> WR;
	std::vector <WWL> WL;
	std::vector <WWL> WLE;

};
std::array <std::array <Chunk, 3>, 3> Ub;
short int XYZ;

void xyz (short int XpostacX, short int ZpostacZ){

	XYZ++;

}

int WINAPI WinMain(HINSTANCE hInstance,	HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	GenBT = std::thread (xyz, 0, 0);
...
}

Przy tym kodzie pojawia się opisany powyżej błąd:

#include <array>
#include <thread>
...

const short int w = 100;
const short int h = 200;

struct Coord{

	short int CX;
	short int CZ;
	short int X;
	short int Y;
	short int Z;

};

struct WWR{

	short int X;
	short int Y;
	short int Z;
	short int R;
	short int K;
	short int Power;

};

struct WySK{

	short int Beg;

	short int Large;
	double P;
	
	bool NewBlock;

	Coord End;

};

struct WWL{

	short int X;
	short int Y;
	short int Z;
	short int R;
	short int Power;

	double C;

	WySK LPr;

};

struct Chunk{

	short int epolx;
	short int epolz;

	bool Rd;

	std::array <std::array <std::array <short int, w>, h>, w> ty;
	std::array <std::array <std::array <short int, w>, h>, w> tK;
	std::array <std::array <std::array <short int, w>, h>, w> tS;
	std::array <std::array <std::array <short int, w>, h>, w> tR;
	std::array <std::array <std::array <short int, 2>, h>, w> Map;

	std::vector <WWR> WR;
	std::vector <WWL> WL;
	std::vector <WWL> WLE;

};
std::array <std::array <Chunk, 3>, 3> Ub;
short int XYZ;

void xyz (short int XpostacX, short int ZpostacZ, Chunk UN){

	XYZ++;

}

int WINAPI WinMain(HINSTANCE hInstance,	HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	GenBT = std::thread (xyz, 0, 0, Ub[1][1]);
...
}

Korzystam z programu Microsoft Visual Studio 2012, v110, windows 7.

3

Błąd powinien wyjaśniać wszystko. std::array nie alokuje dynamicznie pamięci, więc jak kopiujesz element typu Chunk jako parametr funkcji xyz to stosu najwyraźniej nie starcza.

I nie ma w tym nic dziwnego, struktura Chunk jest gigantyczna:

// dla typowego LP64
struct Chunk{
 
    short int epolx; // 2 bajty
    short int epolz; // 2 bajty
 
    bool Rd; // 1 bajt
 
    std::array <std::array <std::array <short int, w>, h>, w> ty; // 2 * 200 * 100 * 200 = 8MB
    std::array <std::array <std::array <short int, w>, h>, w> tK; // 2 * 200 * 100 * 200 = 8MB
    std::array <std::array <std::array <short int, w>, h>, w> tS; // 2 * 200 * 100 * 200 = 8MB
    std::array <std::array <std::array <short int, w>, h>, w> tR; // 2 * 200 * 100 * 200 = 8MB
    std::array <std::array <std::array <short int, 2>, h>, w> Map; // 2 * 2 * 100 * 200 = 80kB
 
    std::vector <WWR> WR; // ≥24 bajty
    std::vector <WWL> WL; // ≥24 bajty
    std::vector <WWL> WLE; // ≥24 bajty
 
};

Czyli ponad 32MB (w sumie padding i wszystko poza gigatablicami można pominąć). Stos ma z reguły 1-8 MB, więc nic dziwnego, że to się nie mieści.

W takim przypadku nie powinieneś przekazywać takiego argumentu przez kopię, tylko przez referencję/wskaźnik. Oczywiście wtedy musisz zadbać o jego czas życia i synchronizację, masz tak naprawdę trzy możliwości:

  • struktura jest globalna/statyczna i read-only i wszystkie wątki mogą z niej korzystać - zwykła referencja będzie ok.
  • struktura nie jest tylko do odczytu, ale wszystkie wątki muszą korzystać z tej samej wersji - referencja i jakiś mutex.
  • struktura powinna być osobna dla każdego wątku - alokujesz pamięć, kopiujesz tam, przekazujesz przez wskaźnik (polecam std::unique_ptr)
0

Struktura ta jest wykorzystywana przez wątek pomocniczy, następnie wątek jest zamykany i główny wątek ma dostęp do struktury.
Uznałem więc, że przekazanie przez referencję tej struktury będzie najlepszym wyjściem, jednak mimo to pojawia się ten sam błąd.

void xyz (short int XpostacX, short int ZpostacZ, Chunk &UN){

	XYZ++;
	pomoc15 = ToString (XYZ);

}
1

Oprócz przyjęcia Chunk& w xyz musisz jeszcze zmienić sposób wywołania dodając wywołanie std::ref do parametru, który ma być przekazany przez referencję:

GenBT = std::thread (xyz, 0, 0, std::ref(Ub[1][1]));
0

Bardzo dziękuję za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1