|
struct CLIENT_DATA
{
int m_nOnlineTime;
int m_nCredits;
};
for a tcp server which would handle at most 10240 clients.
I want to manage all the clients.there are two solutions
1: use a std:map, and a mutex over all map operation
2: use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled.
if I use an array,mutex would only be necessary over the ID operations.such as assign an Id to a client when connected,recycle an Id when a client is disconnected.
in fact,they are not different if I only have to handle connect or disconnect.
but if I want to change the CLIENT_DATA for each client.
for the first solution:I have to lock the whole map;
for the second, I could maintain a mutex in each CLIENT_DATA.
my question is, solution 1 is much more easy to code.solution 2 seems much more efficient.
which one do you prefer?
Thank you.
|
|
|
|
|
Quote: use a std:map, and a mutex over all map operation Only understandable way to do this. But has some constraints. My assumptions won't consider that using a mutex is necessary unless your application allows asynchronous processing + write access for connected devices. If writing process is maintained by your server program, then you know how to do that — Hint: create a condition inside function and don't make it visible in threads, abstract the implementation.
Quote: use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled. How about you don't use this. Suppose if there are only 10 clients connected, C array will still allocate all of the areas in RAM. Totally not worth it, and as you said — Id would be recycled —, how? What is your algorithm for that?
There are many parts missing in your post, such as, what data will they access, are they going to write data too, to same file or not — mutex and thread-safety makes sense if something is happening on same time at different threads, if not then don't worry about this.
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
Ok,let me explain it in details
1 I have to maintain a collection for all the clients data,such as
struct CLIENT_DATA
{
std::string m_strIp;
int m_nOnlineTime;
int m_nCredits;
};
2 the client data update(by a timer for example) and the socket are in different thread
so If I use a map
bool Connect(std::string strIp)
{
boost::lock_guard<boost::mutex> lock(m_lock);
CLIENT_DATA* pData = new CLIENT_DATA;
pData->m_nOnlineTime = 0;
pData->m_strIp = strIp;
m_mapClients.push_back(strIp,pData);
return true;
}
void Disconnect(std::string strIp);
{
boost::lock_guard<boost::mutex> lock(m_lock);
std::map<std::string,CLIENT_DATA*>::iterator iter = m_mapClients.find(strIp);
if(iter != m_mapClients.end())
return;
CLIENT_DATA* pClientData = m_mapClients[strIp];
if(pClientData != NULL)
{
delete pClientData;
pClientData = NULL;
}
m_mapClients.erase(iter);
}
bool UpdateOnlineTime(std::string strIp)
{
boost::lock_guard<boost::mutex> lock(m_lock);
std::map<std::string,CLIENT_DATA*>::iterator iter = m_mapClients.find(strIp);
if(iter != m_mapClients.end())
return false;
CLIENT_DATA* pClientData = m_mapClients[strIp];
if(pClientData == NULL)
return false;
pClientData->m_nOnlineTime += 10;
return true;
}
I have to lock the map use the same mutex in connect,disconnect,updateonlinetime
if I use a array
void PrepareIds()
{
for(int i=0;i<10240;i++)
m_vecAvailableIds.push_back(i);
}
int FetchId()
{
boost::lock_guard<boost::mutex> lock(m_lock);
if(m_vecAvailableIds.size()<=0)
return -1;
int nId = m_vecAvailableIds.back();
m_vecAvailableIds.pop_front();
return nId;
}
int ReturnId(int nId)
{
boost::lock_guard<boost::mutex> lock(m_lock);
m_vecAvailableIds.push_back(nId);
}
bool Connected(std::string strIp)
{
int nNewId = FetchId();
if(nNewId == -1)
return false;
CLIENT_DATA* pData = m_arrClients[nNewId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
pData->m_bInUse = true;
pData->m_nOnlineTime = 0;
pData->m_strIP = strIp;
}
bool Disconnected(int nClientId)
{
Assert(nClientId>=0 && nClientId<10240);
CLIENT_DATA* pData = m_arrClients[nClientId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
pData->m_bInUse = false;
ReturnId(nClientId);
return true;
}
Now,the UpdateOnlineTime function and the CLIENT_DATA structure are changed
struct CLIENT_DATA
{
std::string m_strIp;
int m_nOnlineTime;
int m_nCredits;
bool m_bInUse;
boost::mutex m_mutex_data;
};
bool UpdateOnlineTime(int nClientId)
{
Assert(nClientId>=0 && nClientId<10240);
CLIENT_DATA* pData = m_arrClients[nClientId];
boost::lock_guard<boost::mutex> lock(pData->m_mutex_lock);
if(! pClientData->m_bIsInUse)
return false;
pClientData->m_nOnlineTime += 10;
return true;
}
There is only need to lock one CLIENT_DATA in case we may update the m_nCredits in some other place.
Now there are two kinds of mutex,one for Ids,one for each CLIENT_DATA
the most important point is when I iterate all the client datas
if I use a map:
UpdateClients()
{
boost::lock_guard<boost::mutex> lock(m_lock);
for(int i=0;i<m_mapClients.size();i++)
{
Update();
}
}
if I use an array
UpdateClients()
{
for(int i=0;i<m_arrClients.size();i++)
{
Update();
}
}
if the map size if very large,such as 10240;
lock the whole map would block the connect or disconnect operation.
modified 21-Nov-16 5:35am.
|
|
|
|
|
Some thoughts about your posts (the initial one and the above reply to Afzaal Ahmad Zeeshan).
Do you really need to store the IP? If so, don't store it as string.
There is no need to generate a (re-usable) connect ID. You already have one:
The connection socket handle.
Using the handle avoids also storing the IP because you can get the IP from the handle using getpeername . But using the handle makes using a map more appropriate.
There is also a solution to avoid locking at all:
Just let the functions be executed in the same thread. As far as I understand there are three events: connection, disconnection, and periodical updates. If connection and disconnection are events issued from other threads, implement signaling functions passing the socket handle.
My suggestion:
Use a map storing the socket handle and avoid locking by putting all associated functions into a single thread.
|
|
|
|
|
thank you
in fact there are two threads.
Thread A would get some CLIENT_DATA pointer to do something frequently,but would not change the map
Thread B Is the update thread include handling connect and disconnect,the map would only be changed here.
so If I update the map in thread B, It should be locked while updating.
it would block the Thread A at somewhere like GetClientData(int nClientId);
solution 2 is designed to avoid locking the whole CLIENT_DATA collection in Thread B.
my question is:
If the map is not vary large,use a std::map is fine,but if the collection of CLIENT_DATA is very large,
such as 10240,Is std::map ok?
|
|
|
|
|
So you have these conditions:
connect and disconnect
Seldom, single add / remove. Locking is no problem.
update
Periodically, all items must be accessed. Locking is a problem when updating requires a significant time.
query
Single? access in peridocally? short/long? intervals.
If locking is a problem depends on query frequency and number of items.
So it seems that only updating is critical. But as I understood you will update all items at once and know the max. number of items. Regardless of the choosen storage type, the first optimisation is reserving the required memory to avoid re-allocations and avoid members that use dynamic memory allocation like std::string .
So your requirements are:
- Inserting and deleting performance is not critical
- Iterating over all items is critical
- Accessing single items is not critical?
When using a map, use an unordered_map because it satifies the above (fast iterating over all elements but slow iterating over a subset of the elements).
When using an array, list, or vector, you have to perform a find to access single elements (which is also there but hidden when using a map).
When using a pre-allocated C array you have to implement also functions to add and remove elements where adding is simple (append) but removing requires moving memory. But this will be probably the fastest option when iterating over all items.
But I don't think that the performance of a plain C array is much better than using a container iterator (note that you must use the iterator rather then using the at or [] operator because that result in a lookup with maps and include out of range checks with other container types).
You may implement different versions and benchmark them to see the differences. But a max. number of 10240 should be not critical.
|
|
|
|
|
thank you very much
I would try and test it.
|
|
|
|
|
Hi
I created an event With the Following parameters CreateEvent(NULL,FLASE,FALSE,NULL);
From what I understand the third parameter says what the initial state of the object is
Signaled or NON signaled if it is FALSE non signaled the first time I executed the
WaitForSingleObject my thread will return and in addition set the object to signaled
Meaning all threads will have to wait till I call SetEvent
Thing is the first time around the executing thread never returns
|
|
|
|
|
I think you've got the meaning of "signalled" the wrong way around. The wait function will return only when the event is signalled. An auto-reset event will automatically reset the event to non-signalled when it returns, and manual reset event will not. Use the SetEvent to release other threads, or the ResetEvent to block other threads.
Think of the event of some operation that has to happen in your code. Other threads need to wait for that operation to complete. Once it has been completed, you signal the other threads that it is ok to proceed.
Cheers,
Mick
------------------------------------------------
It doesn't matter how often or hard you fall on your arse, eventually you'll roll over and land on your feet.
|
|
|
|
|
Okay how about the second parameter to CreateEvent if that is FALSE does that mean that after
a signal'ed event returns right away from WaitForSingleObject Windows will Automatically turn the event to NON signalled
|
|
|
|
|
Yes, it does. bManual = FALSE means that it is an Automatic ResetEvent after a wait operation.
Cheers,
Mick
------------------------------------------------
It doesn't matter how often or hard you fall on your arse, eventually you'll roll over and land on your feet.
|
|
|
|
|
Hello experts!!!
There is a component for Visual Studio C ++ "assimp" (Open Asset Import Library).
With the help of "assimp" on the screen built scene with a 3D object.
Can I with the help of "assimp" export the scene image with a 3D object into graphical file, for example BMP or JPEG?

|
|
|
|
|
Looking at the site, the package it already does that via it's viewer (open3mod).
They call it a "screenshot" although more technically it is a render. They are inserting a camera position against the 3D model in a 3D space and rendering what would be seen. You would have to do the same.
|
|
|
|
|
I like to live dangerously so I'll risk forum or administration wrath with this one.
Found this Linux application which supposedly helps with file linking.
I have created using pkg_config - "opencv.pc" file and added it in -L - add library path.
It does contain OpenCV libraries , I verified that, but linker complain of "incorrect extension ".
However, I cannot find in any pkg_config related sites HOW to actually tell GCC linker to use this "opencv.pc".
Also this pkg_config info is not that new. There is no open access user forum which makes me suspicious if this "packaging libraries " is a good and useful tool.
Please, if this post is not in line with CodeProject policies just ignore it or let me know and I'll delete it.
Cheers
Vaclav
|
|
|
|
|
I think you are making life more complicated than it needs to be. This is just another utility that you will need to learn ... see pkg-config(1) - Linux man page[^].
|
|
|
|
|
... or enter "man pkg-config" at a shell prompt.
|
|
|
|
|
The 'man' command is the first thing one needs to learn when working on Unix/Linux.
|
|
|
|
|
Thanks for lectures. I 'll let you know HOW to actually tell GCC linker to use this "opencv.pc". when I answer my own question.
Cheers
Vaclav
|
|
|
|
|
No lectures, just advice. Unfortunately your question is not detailed enough for a better answer.
|
|
|
|
|
Vaclav_Sal wrote: However, I cannot find in any pkg_config related sites HOW to actually tell GCC linker to use this "opencv.pc".
The linker doesn't use .pc files. You must use the pkg-config command to generate the options for the compiler or linker. Use command substitution[^] to embed the pkg-config command on the linker command line or to store the output in a variable.
|
|
|
|
|
Thanks for actually answering my question without an additional commentaries.
Appreciate that.
I have also found that I could include the pkg_config command(s) in "make" file.
Of course I need to figure out how to either modify the "make" automatically build by IDE or learn how to build my own.
Cheers
Vaclav
|
|
|
|
|
Still struggling with the issue
Here is exact syntax I have used - it suppose to "print" , I assume substitute, the libraries in package ( opencv ) to the linker as -l options.
It does not matter if the options are --libs opencv or opencv --libs - which is expected.
"$(pkg-config opencv --libs)"
Here is partial liker output
make all
Building target: TEST_1
Invoking: GCC C++ Linker
<b>g++: error: missing argument to ‘-l’</b>
g++ -L/usr/local/lib -o "TEST_1" ./src/TEST_1.o <b>-l""</b>
make: *** [TEST_1] Error 1
makefile:45: recipe for target 'TEST_1' failed
I have tried different format / syntax and "$(command)" is correct per the link you have provided. From the output it is notable that no -l files were included - -l"".
I do not know what else can be wrong. The command does not expands to anything linker can use and it should look as terminal output.
jim-desktop $ pkg-config opencv --libs
-L/usr/local/lib -lopencv_shape -lopencv_stitching -lopencv_objdetect -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_viz -lopencv_core
I have asked in several forums and all I am getting is how to add -L/-l options MANUALLY to the linker options.
BTW including ":" before the manually inserted file name specifies to the pkg-config to use library file WITHOUT using the file extension. Nice to know but does not solve my issue.
Cheers
Vaclav
|
|
|
|
|
Hi All,
In my MFC project, some Text box should appear in UI for 32 bit builds and that is not appear for 64 bit builds.
For this I have added the following piece of code in Resource.h file
Resource.h:
#ifndef _WIN64
#define INCLUDE_32_BUILDS 1
#endif
#ifdef INCLUDE_32_BUILDS
#define IDC_GS_CMB_TYPE 5176
#endif
and the code in the resource file is:
#ifdef INCLUDE_32_BUILDS
LTEXT "Receiver Output Protocol :",IDC_STATIC,16,42,123,8
EDITTEXT IDC_GS_EDIT_TYPE, 150, 42, 84, 85, ES_AUTOHSCROLL | ES_READONLY
#endif
I want to show above text box for only 32 bit application and not in 64 bit application
I am able to compile the code successfully, but still I am able to see the above text in UI for 64 bit application. I think #ifdef INCLUDE_32_BUILDS is not working properly in resource file.
Please let me know how to make sure that the #ifdef INCLUDE_32_BUILDS work and the text box should not appear for 64 bit application?
Thanks,
Lakshmi.
modified 17-Nov-16 23:35pm.
|
|
|
|
|
You need to ensure that your .rc file has access to that defined value. Either add it via a #include d header file, or in your project properties.
|
|
|
|
|
Expanding Richards answer the resource compiler does not have access to the standard C preprocessor predefined macros because you haven't included any of the standard headers
_WIN64 whilst a standard predefined macro in the C preprocessor is not predefined in the resource compiler. So your #ifdef _WIN64 is failing because _WIN64 doesn't exist to the resource compiler.
And trying to do so you usually need to use RC invoke to go around some stuff the header files contain:
RC with predefined Macros (Windows)[^]
So Resource compiler starts with exactly one macro RC_INVOKED and includes only macros that are included in it's include section. Once upon a time there was an undocumented _WIN32 but I think even that has gone these days.
So the more usual trick is to use the build options tab on the resource file to preset a define. On your resource build you have configurations and you can add predefined macros.
Config Properties -> Resources -> General In the macros tab add _WIN64 manually to the 64 bit build. Add _WIN32 to the 32 bit build tab.
In vino veritas
|
|
|
|