silentshark wrote: ↑Sat Aug 15, 2020 7:13 pm
With the nasty legacy code I have (lots of global variables etc.), the multiple process approach might be the easiest thing for me to use.
So, here's my lazy question, what's the easiest way to create multiple processes and share memory between them, in the world of Windows?
And that's exactly the reason I did it - tons of global variables due to a first-time engine writer.
It's easy to create background processes in Windows. Here's my code:
Code: Select all
void StartProcesses(int nCPUs)
{
if ((nCPUs > 1) && !bSlave)
{
int n;
char commandline[256];
// create slave processes
for (n = 0; n < nCPUs - 1; n++)
{
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(si);
ZeroMemory(&pi[n], sizeof(pi[n]));
sprintf(commandline, "\"%s\" slave sharedmem=%s sharedhash=%s numslave=%d", szProgName, szSharedMemName, szSharedHashName, n);
printf("Launching slave process %d with '%s'\n", n, commandline);
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
commandline,
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // No creation flags, no console window
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi[n] ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
}
}
}
}
Creating the shared memory almost as easy. There are plenty of code examples you can find, but here's mine. You probably shouldn't use it because I suspect it's crap. But, as I said, at least it worked.
Code: Select all
#if USE_SMP
typedef union hilo {
unsigned long a[2];
unsigned long long b;
} hilo;
if (!bSlave) // master process
{
// create shared memory for slave processes (even if they're aren't any, because of the "cores" command)
time_t t;
hilo h={0};
h.b = dwHashSize * sizeof (HASH_ENTRY) + dwPawnHashSize * sizeof (PAWN_HASH_ENTRY) + dwEvalHashSize * sizeof (EVAL_HASH_ENTRY);
sprintf(szSharedHashName, "MSH-%lld", (long long) time(&t));
sprintf(szSharedMemName, "MSM-%lld", (long long) time(&t));
hSharedHash = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
h.a[1], // maximum object size (high-order DWORD)
h.a[0], // maximum object size (low-order DWORD)
szSharedHashName); // name of mapping object
if (hSharedHash != NULL)
{
HashTable = (HASH_ENTRY *)MapViewOfFile(hSharedHash, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
0);
PawnHashTable = (PAWN_HASH_ENTRY *) ((char *) HashTable + dwHashSize * sizeof (HASH_ENTRY));
EvalHashTable = (EVAL_HASH_ENTRY *) ((char *) PawnHashTable + dwPawnHashSize * sizeof (PAWN_HASH_ENTRY));
if (HashTable)
ClearHash();
}
hSharedMem = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
sizeof(SHARED_MEM), // maximum object size (low-order DWORD)
szSharedMemName); // name of mapping object
if (hSharedMem != NULL)
{
smSharedMem = (PSHARED_MEM) MapViewOfFile(hSharedMem, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(SHARED_MEM));
}
}
else if (bSlave) // all other processes
{
hSharedHash = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szSharedHashName); // name of mapping object
if (hSharedHash != NULL)
{
HashTable = (HASH_ENTRY *)MapViewOfFile(hSharedHash, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
dwHashSize * sizeof (HASH_ENTRY) + dwPawnHashSize * sizeof (PAWN_HASH_ENTRY) + dwEvalHashSize * sizeof (EVAL_HASH_ENTRY));
PawnHashTable = (PAWN_HASH_ENTRY *) ((char *) HashTable + dwHashSize * sizeof (HASH_ENTRY));
EvalHashTable = (EVAL_HASH_ENTRY *) ((char *) PawnHashTable + dwPawnHashSize * sizeof (PAWN_HASH_ENTRY));
}
hSharedMem = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szSharedMemName); // name of mapping object
if (hSharedMem != NULL)
{
smSharedMem = (PSHARED_MEM)MapViewOfFile(hSharedMem, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(SHARED_MEM));
ZeroMemory(&smSharedMem->sdSlaveData[nSlaveNum], sizeof(SLAVE_DATA));
}
}