albinopapa wrote:Why should 0/NULL not be interchangeable? Since the introduction of nullptr, NULL for a null'd pointer has lost it's meaning in my eyes, and NULL is just a macro defined to be 0, so I think it's perfectly fine to use NULL and 0 interchangeably.
NULL has not lost it's meaning of being used for pointers, in-fact it should not be used at all now and nullptr should only be used. Using NULL makes it unclear to the reader what the argument being specified is. Additionally you will potentially get warnings from different compilers and static analysis.
albinopapa wrote:The usage of std::thread over the Win API CreateThread seems odd to me, just because I'm ignorant of implementation specifics. Some of the C++ implementation in MSVC are just wrappers for the Windows API, so if programming for Windows it would make since to just use the Win API right? I understand about if you want portability, you should use the C++ standard library though.
std::thread has many benefits:
* Using RAII doesn't get the handle leak currently in this code
* Usage of a callable prevents the undefined behaviour with the casting of function pointers
* Cross-platform
* Easier to use
The Windows API is old, and quiet awful if you have something from the standard exists to do what you want use it instead of using the Windows API, it will generally be better for alot of the same reasons. The Windows API is designed for usage with "C" so has all the issues of a C API. If you want to use Windows specific APIs maybe look at WinRT
albinopapa wrote:Just out of curiosity reductor, what do you do for a living? You have a lot of suggestions about coding style and are pretty knowledgeable of C++ in general, are you in the industry?
I've been programming C++ for around 16 years (Released my first project back in 2000 -- Bots for Half-life 1), and also do it professionally working as a Senior Software Engineer on a large (Guiness world record breaking) MMO engine.
Pindrought wrote:Thank you very much for the feedback/suggestions reductor. I don't think I know it all or anything so I really appreciate all of the information I can get. The only reason I was using NULL when I was using it, was because all of the code I had learned from was using NULL. Now that I see that it may be confusing since it does not return a ptr, I will refrain from using NULL in the future.
Not a problem, I'm always open to giving feedback. If you want me to review anything just send me a PM.
I have some questions about your notes.
Pindrought wrote:reductor wrote:
Tutorial 1:
- The comment on inet_addr( "127.0.0.1") says broadcast locally, this has nothing to do with broadcasting
What is the correct terminology for what I was saying? I meant that only clients on the same router would be able to connect since the server was only "broadcasting" (I know now that this is the wrong term) locally.
This is called the loopback address ( INADDR_LOOPBACK ), this does not make it so only clients on the same router can see the connected clients it means only that local machine can access it via it's loopback interface.
Pindrought wrote:reductor wrote:
Tutorial 2
- Your function pointer being a different signature is going to lead to undefined behaviour, your just lucky the ABI is allowing this, but will break at some point. The client is going to have some issues if you return from it because of the left over parameters.
Is there any way you could clarify this for me? I'm going to look into it, but i'm not sure what you mean about the function ptr being a different signature.
Code: Select all
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL);
void Client::ClientThread()
The issue here is that the function is actually called with an LPVOID argument, causing it to be left on the stack (or within a register), this is undefined behaviour and can cause any number of things (Crashes, Issues when thread finishes, Unicorns to fly)
Pindrought wrote:reductor wrote:Tutorial 6
- That static global means a file local variable, you should never have a static variable in a header file
I know it is rigged up, but how do you suggest accessing the Server class from the threads? This was the simplest work around I could find, but if there is a right way to do it, i'd rather take that route. Should I just use std::thread and pass a ptr to the server class in the thread parms?
For global variables exposed to multiple different files you should use
Code: Select all
// server.h
extern Server * pServer;
// server.cpp
Server * pServer;
However for this you should be using std::thread and pass the pointer to the class via parameters, this is well defined, type-safe, and clear what is going on.
Pindrought wrote:reductor wrote:Tutorial 11
- You still have race conditions with your mutexes, e.g. Server::PacketSenderThread can be using connections when it is changing (and various other places)
Could you clarify this part? I am having issues seeing how there is a race condition in the PacketSenderThread.
Server::ListenForNewConnection can be adding a new item to the 'connections' vector which can move around the internal pointers within the vector. At the same time PacketSenderThread can be using the same pointer while iterating the vector. Not to mention all the other places where your using connections.
To simplify things and chances of race conditions you should have ClientHandlerThread take an argument for std::shared_ptr<Connection> (using std::thread), and it should stop using connection[id] as everytime this happens it should have the mutex. As you have a combination of read/write for connections you could use std::shared_mutex then just unique_lock for your writes/resizes and shared_ptr for any reads.