dimanche 19 avril 2015

IPC, sychronization, shared memory and mutex performance

I'm currently testing what my options are in order to communicate between 2 processes using shared memory while synchronizing their access to said shared memory and preventing data races with mutex.


Everything works perfectly well, except that the performance seems to be... quite poor. I was wondering if it was because of the inherent performances of mutex or if if it's simply my implementation that is wrong.


Here is the code for my shared memory class:



#ifndef SHAREDMEM_H
#define SHAREDMEM_H

#include <Windows.h>

class SharedMemMng
{
public:
SharedMemMng();

class SharedMem
{
friend class SharedMemMng;
private:
SharedMem();

void increaseCount();

int count() const;
bool isReady() const;

void setReady(bool status);

int m_counter;
bool m_isReady;
};

void setMem(SharedMem* mem)
{
m_mem = mem;
}

SharedMem* mem() const
{
return m_mem;
}

void increaseCount();

int count() const;
bool isReady() const;

void setReady(bool status);

private:
SharedMem* m_mem;
HANDLE m_hCounterMutex;
HANDLE m_hIsReadyMutex;
};


typedef SharedMemMng::SharedMem* SharedMem;


/*
* SHARED MEMORY MANAGER
*/

SharedMemMng::SharedMemMng()
{
m_hCounterMutex = CreateMutex(NULL, FALSE, "MyCounterMutex");
m_hIsReadyMutex = CreateMutex(NULL, FALSE, "MyReadyMutex");
}

void SharedMemMng::increaseCount()
{
WaitForSingleObject(m_hCounterMutex, INFINITE);
m_mem->increaseCount();
ReleaseMutex(m_hCounterMutex);
}

int SharedMemMng::count() const
{
WaitForSingleObject(m_hCounterMutex, INFINITE);
int result = m_mem->count();
ReleaseMutex(m_hCounterMutex);

return result;
}

bool SharedMemMng::isReady() const
{
WaitForSingleObject(m_hIsReadyMutex, INFINITE);
bool result = m_mem->isReady();
ReleaseMutex(m_hIsReadyMutex);

return result;
}

void SharedMemMng::setReady(bool status)
{
WaitForSingleObject(m_hIsReadyMutex, INFINITE);
m_mem->setReady(status);
ReleaseMutex(m_hIsReadyMutex);
}


/*
* SHARED MEMORY
*/

void SharedMemMng::SharedMem::increaseCount()
{
m_counter++;
}

int SharedMemMng::SharedMem::count() const
{
return m_counter;
}

bool SharedMemMng::SharedMem::isReady() const
{
return m_isReady;
}

void SharedMemMng::SharedMem::setReady(bool status)
{
m_isReady = status;
}

#endif //SHAREDMEM_H


The first process:



#include <Windows.h>
#include <stdio.h>
#include <ctime>
#include "sharedmem.h"

int main()
{
SharedMemMng m_sharedMemMng;

HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0,
sizeof(SharedMem),
"MySharedMem");

m_sharedMemMng.setMem((SharedMem)MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0,
sizeof(SharedMem)));

LONG test = 0;
clock_t start = clock();
for (int i = 0; i < 4000000; i++)
{
InterlockedIncrement(&test);
}
printf("result: %d (%d)\n", clock() - start, test);

clock_t start2 = clock();
for (int i = 0; i < 4000000; i++)
{
m_sharedMemMng.increaseCount();
}
printf("result2: %d\n", clock() - start2);

while (!m_sharedMemMng.isReady());

clock_t start3 = clock();
for (int i = 0; i < 2000000; i++)
{
m_sharedMemMng.increaseCount();
}
printf("result3: %d\n", clock() - start3);

while (true)
{
printf("%d\n", m_sharedMemMng.count());
Sleep(2000);
}

system("pause");

}


And the second process:



#include <Windows.h>
#include <mutex>
#include "sharedmem.h"

int main()
{
HANDLE hMapFile = NULL;
SharedMemMng m_sharedMemMng;

while(hMapFile == NULL || m_sharedMemMng.mem() == NULL)
{
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "MySharedMem");

m_sharedMemMng.setMem((SharedMem) MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0,
sizeof(SharedMem)));
Sleep(200);
}

m_sharedMemMng.setReady(true);

for (int i = 0; i < 2000000; i++)
{
m_sharedMemMng.increaseCount();
}

while (true)
{
printf("%d\n", m_sharedMemMng.count());
Sleep(2000);
}

system("pause");
}


The first test (InterlockedIncrement with only one process): 38 ms. The second test (increaseCount with only one process): 2000 ms. Longer than I expected, but it's okay. The third test: (increaseCount with 2 processes): 10000 ms.


So, am I doing something wrong when implementing my mutexes, or are mutex simply not the appropriate tools for this?


Aucun commentaire:

Enregistrer un commentaire