I have a network application F
. It receives requests from one (or many) client network function. F
can handle multi-client requests using an epoll
loop. F
maintains a state machine for each client(user). F
also maintains some context for each user or client. Whenever a message is received from a client network function (by one user), F
processes the message and if required fetch context specific to this user and updates the context.
Currently, the contexts of different users are maintained in a C++ STL map.
map<clientId,context> userMap;
where clientId
is an integer and context
is a struct
containing user-specific data. Whenever I need to access the userMap I would take a lock first, access the data, and then unlock.
For example, if a client sends a request message X
. The server F
, epoll_wait()
will get the event (i.e. the incoming message). Then this messages is read from the socket and processed further. In the server handleX()
method will be invoked (if user state and context is consistent and allows for handleX
to be executed for this user). Each of these handleX
function needs the current user context for some computation. it locks the userMap, gets or set the data, and then unlocks it.
In the single threaded version of F
, a single thread only waits for events and processes those events one by one.
I tried to use a thread pool to check the multicore scalability of F
. In this case, a single thread reads the messages from the socket and puts those messages in a queue. A pool of threads are waiting on the queue and picks any messages that pushed on the queue. But the throughput is not better than single-threaded code version of F
.
I think locking is inherently serializing the F
's code. I would like to know is there any other model of user context store and retrieve to minimize lock contention?