Click here to Skip to main content
15,886,736 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I am new to C++. I know the basics of C++ overall but I haven't done any multithreading or socket programming so far. So could you please guide me or refer me some links or eBooks where I could find some solid basic understanding about socket programming and multi threading? I searched on web but unable to find any solid materials which explain the things from basic. It would be very grateful if you could help me.
Posted
Comments
Volynsky Alex 8-Aug-12 19:01pm    
Try to read following article:
Try read following articles:
http://www.codeproject.com/Articles/13071/Programming-Windows-TCP-Sockets-in-C-for-the-Begin
http://net.pku.edu.cn/~course/cs501/2011/code/BSD_Socket.t/sockets.pdf
http://www.youtube.com/watch?v=NIqYwXcUdn0
http://www.youtube.com/watch?v=WaLQ7s1X6wo

These 2 topics are very hard even one-by-one. If you want to start only with one of them then choose threading because that isn't dependent on socket programming. I understand if you wanna go on with threading+sockets because this way you use your threading knowledge to do something useful, but you have to invest a lot of time to find out network related issues too and often you will have some hard time to find out if a bug is caused by incorrect multithreading or some socket handling problems! Here is a question on stackoverflow:
http://stackoverflow.com/questions/149163/patterns-for-multithreaded-network-server-in-c-sharp[^]
The accepted answer contains multithreaded C++ tutorials with network coding, might be what you want.

If I were you I would start with threading first. This is also the base for a lot of networking solutions. That is a very big task itself and at least you will not be confused when you face a bug. I did lot of crossplatform multithreading in C++ so I can tell you what is the most important stuff in my opinion. I assume that you are a beginner and I remember that threading in C++ was a mistery + pain in the ass for first so I can give you a starter kick. If you are just much better than I expected then just ignore whats following:

So you have a thread and you have some synchronization primitives that you will have to use often: mostly locks (aka critical sections / mutexes) and events. There are other types of synchronization primitives too but you can solve almost all kind of problems with these two primitives and I dont want to discuss other primitives yet.

What you should do is encapsulating the thread and the synchronization primitives into their own classes. Encapsulating a thread in C++ is a bit tricky so I link you an example that looks OK by its interface, I havent tried/checked its correctness though:
http://jrdodds.blogs.com/blog/2006/06/encapsulating_a.html[^]
What I like in the linked thread implementaiton is that its simple. One thing you have to modify in it is that you should change the run method to a pure virtual void run() that is protected and overrideable by descendant thread classes that you derive from it. Another thing I don't like in it is that it starts the thread from its constructor and its a bad practice to do something in the constructor if it can fail. Put this code from the constructor to a bool start() method that can return errors for you.

Note that a thread object has only these operations: start, and wait(join). It also has a pure virtual run() or execute() method that will contain the thread code to execute in your derived thread classes. Never perform other than start/wait on a thread because: it is always a bad design pattern to use terminate/suspend/resume - everything can be solved without these clearly with a nice solution so ask a question on codeproject if you cant solve something withtout these. avoiding these dangerous operations also help you to write crossplatform code because thread start and wait/join is present on all platforms. If you want to stop a thread then instead of terminate put a method into your thread class that somehow asks the working thread to exit (for example by setting a terminate request flag and waking up the thread if needed) and after this wait for the thread to terminate. If you create and start a thread object then the story should always end by waiting for the thread to terminate and then deleting the thread object. (There are some exceptions to this when the thread must delete itself but that requires a bit more complicated thread implemenation than what I linked, and you dont need at for now, going without that as a start is better.)

After this you should write a lock class and an event class. You can do it by yourself! :-)
A lock object has 2 methods: Lock() and Unlock(), an event object has a Set() and a Reset() and a Wait() method (A good Wait() method has a timeout parameter in milliseconds and returns a bool that indicates whether wait returns as a result of a timeout or because the event was already set or became set). For locking ppl usually write a scoped lock helper class or helper template that is very useful, I mention it because it is used in a lot of example programs, search for "scoped lock" if you are interested but you can leave this for later because its just a piece of sugar on top of the previous things. (Just a sidenote: put the copy constructor and the assignment operator of your threading classes to private to prevent copying them because that causes brutal bugs especially if you are new to C++.)

Here is an example lock class from one of my old progs (windows):
C++
class CLock
{
public:
    CLock()
    {
        InitializeCriticalSection(&m_criticalSection);
    }
    ~CLock()
    {
        DeleteCriticalSection(&m_criticalSection);
    }
    void Lock()
    {
        EnterCriticalSection(&m_criticalSection);
    }
    void Unlock()
    {
        LeaveCriticalSection(&m_criticalSection);
    }

private:
    CLock(const CLock&);
    CLock& operator=(const CLock&);

private:
    CRITICAL_SECTION m_criticalSection;
};


And a scoped lock class that can be used with the previous lock class:
C++
class CScopedLock
{
public:
    CScopedLock(CLock& lock) : m_lock(lock) { m_lock.Lock(); }
    ~CScopedLock() { m_lock.Unlock(); }
private:
    CScopedLock(const CScopedLock&);
    CScopedLock& operator=(const CScopedLock&);
private:
    CLock& m_lock;
};


Event class:
C++
class CEvent
{
public:
    CEvent(bool initialState=false) : m_signaled(initialState)
    { 
        m_hEvent = CreateEvent(NULL, TRUE, initialState?TRUE:FALSE, NULL); 
        assert(m_hEvent);
    }
    ~CEvent() 
    { 
        CloseHandle(m_hEvent); 
    }
    void Set()
    {
        SetEvent(m_hEvent);
    }
    void Reset()
    {
        ResetEvent(m_hEvent);
    }
    bool IsSet()
    {
        return Wait(0);
    }
    static const uint32 INFINITE_WAIT = UINT32_MAX;
    // The return value is true if the event is set.
    // milliseconds=CEvent::INFINITE_WAIT waits forever, milliseconds=0 just polls.
    bool Wait(uint32 milliseconds=CEvent::INFINITE_WAIT) 
    { 
        return WaitForSingleObject(m_hEvent, (milliseconds==CEvent::INFINITE_WAIT ? INFINITE : milliseconds)) == WAIT_OBJECT_0;
    }
private:
    CEvent(const CEvent&);
    CEvent& operator=(const CEvent&);
    HANDLE m_hEvent;
};



Now you can derive your own thread class and implement its run() method. As a first attempt try to implement your own thread class, create and execute this thread from your main, do some fancy stuff in the thread (printf something, flush it, and wait for 3 seconds :D) and on the main thread wait for this thread object then delete it, printf something and exit.

If you was successful with the first task, then here is the second: Implement a thread class that has a counter starts from zero. The thread does this in a loop: always incrments this counter, prints it, then waits for 1 second. On the main thread wait for keyboard input and if the user presses enter then ask the worker thread to finish and then wait for it to actually return from its run() method and then quit the program. You can do that by putting in your own RequestExit() method in your thread that does nothing just sets a request exit flag member variable in the thread object and you should check this in your infinite loop in your thread code and break out of the loop if an exit was requested. As you see after pressing enter the actual program quit might take up to 1 minutes because of the wait in the loop. You can do a much better solution if your event class has a nice wait method. In this case instead of the requestexit flag you should put in an event that is initially not set. In your worker thread loop you are using the Wait() method of this event with 1 sec timeout instead of a Sleep() call, and when Wait() returns you check its bool return value if it returned because of a timeout, if yes then you continue the loop, otherwise you end the loop and return from the run() method of your thread class.

For inter-thread communitaion one of the most basic and useful building blocks is the blocking message queue. It is used for one way communication between a worker thread, and one or more other threads that give work to the worker thread. The interface of a blocking message queue is very simple: It has a PutItem() and a GetItem() method. PutItem() is used by the "producer threads" and GetItem() is used by the "consumer thread" aka the worker thread. GetItem() removes an item from the queue, but if there is no item in the queue then it blocks until another thread puts in something by calling PutItem(). PutItem() puts something to the queue and always returns immediately. In some blocking queue implementations there is a maximum item capacity and there PutItem() can also block if the queue is full when PutItem() is called.
The one with the capacity is slightly more complex, here you can find a good example to that: http://stackoverflow.com/questions/11706985/win32-thread-safe-queue-implementation-using-native-windows-api[^]
You next task: using the example link write your own blocking queue implemenation that is a template and you can specify the type of the items. Use your own Lock and Event classes. Try to write a queue that has a maximum capacity and try to write one with infinite capacity (the latter is easier).

When you ready with your blocking queue template write this example program:
Define this interface:
C++
class ITask
{
public:
    virtual ~ITask() {}
    virtual void Execute() = 0;
};

Create a worker thread class that has a blocking queue template that stores ITask pointers. The thread class should have a run() method that does the following:
In an infinite loop it always removes an ITask pointer from the blocking queue. If the pointer is NULL, then the thread breaks out from the infinite loop and returns from run(), otherwise it calls the Execute() method on the pointer then deletes the task object and continues the loop. You should write an AddTask(ITask*) method for your thread class that puts a task to the blocking queue of the thread.
Now derive a task object from ITask, and override its Execute() method, the code should do something (printf) and then wait for 1 second.
On the main thread create the previously implemented thread and start it. After this create 5 task objects and add them to your thread object by calling its AddTask() method, then wait for the thread and exit.

If you want to know on a thread when a task is finished by the worker then you can do 2 things:
1. you put the task to the worker thread and at the end of the task code you set an event variable and on the other thread you wait for this event.
2. both threads have a message queue and when the task finishes it can put in a task to the message queue of the other thread that will be executed by the other thread sometime when it is finished with its current work. Gui systems are usually driven by a single thread that has a message queue. If you start for example a copy operation with a progress bar you can not do that on the gui thread because then the user interface becomes "frozen", non-responsive. Instead you do copying in a task executed by a worker thread, and that worker thread can send messages to the gui thread via its message queue. It might send progress updates to refresh a progress bar or when the operation is finished. On windows you put a message to the gui message queue with the PostMessage() WinApi call by sending a WM_USER+x message to a window.
As your next task you can write an example console program that simulates the file copying in a gui program. It should have a main thread and 2 other threads both having a message queue. The main thread just starts the worker thread, and then the thread that simulates the gui, after this it should wait for the two threads to finish, one after the other. The gui thread should have a reference to the worker thread. You write a task that simulates file copy and from the gui thread you should put it into the queue of the worker thread. after this the gui thread does nothing gets items from its message queue and prints out the progress. Int the gui thread you dont need task interfaces in your queue, you are ok with a simple integer that is the progress (percentage) of the file copy. the gui thread should just give the filecopy task to the worker thread then receiving and printing progress until it reaches 100%. when the progress reaches 100% the gui thread breaks from its loop, puts a NULL task to the queue of the worker thread to ask it to return from its run() and then the gui thread itself returns from run(). The main method successfully ends waiting for the threads and your program returns. Your file copy task must have a reference to the gui thread and in a loop it should increment a progress value, send it to the queue of the gui thread and then wait for some time (1 sec).

If you completed the above tasks you have a grasp about the implementation of a simple C++ threading library and you know how to put simple tasks to worker threads and you know how to communicate between threads easily. You can now go on by reading and trying more and more stuff. If you are new to threading then learn some theory from here: http://en.wikipedia.org/wiki/Concurrency_pattern[^]
Even if you know these patterns implement them in C++.
After this you can go on with searching for network tutorials and books. I recommend searching for books on amazon among the ones that have a lot of good reviews, the book Philip Stuyck recommended is also a good classic book on network coding.
 
Share this answer
 
v3
Comments
SoMad 8-Aug-12 18:25pm    
Dude! No reason to recommend a book when you can write one as a solution :) +5.

Soren Madsen
pasztorpisti 8-Aug-12 18:30pm    
Thank you!
Its not a book, just a novel! :-) Even if its short to fill a book, a good CP article could come out about the topic with lots of code samples...
Kenneth Haugland 8-Aug-12 19:02pm    
Have a 5 for your trouble :)
pasztorpisti 8-Aug-12 19:09pm    
Thanks! :-)
Albert Holguin 14-Feb-13 10:35am    
lol, my thoughts exactly!
I bought myself an excellent book about socket programming, it gives all the information you need about the involved protocols too.
Unix network programming : The sockets networking api volume 1 Addison wesley.
The same book also handles the threading stuff because it goes hand in hand with sockets.
On top of this. Multi threaded programming and socket programming is advanced material. Not to be taken lightly. It will take you a lot of practice, experimentation and knowledge of the underlying protocols to really get somewhere. That book is really worth the investment.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 8-Aug-12 16:34pm    
Agree, a 5.
--SA
Volynsky Alex 8-Aug-12 16:57pm    
+5!
SoMad 8-Aug-12 18:26pm    
Ok, but one of you forgot to actually vote for Philip's solution :)

Soren Madsen
A beginner in C++ 9-Aug-12 7:34am    
Philip,

Can u provide me any link to download the book in e-version??? :-p
pasztorpisti 9-Aug-12 8:20am    
I don't think its allowed to submit warez links here. :D Use google, you will find it for sure either in a legal or illegal way because its a famous book and it has ebook version ;-)
A good solution is to use boost library with asio.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900