Multi-threading is in essence multiple programs running at the same time as part of single application, as if there were multiple cpu's and in some cases there are multiple cpu's.
One common usage of multiple threading is when an application has to deal with one or more external events, that take a significant amount of time to complete. The goal is to continue processing while these events are in progress.
These multiple threads needs a way to communicate with each other. Sometimes all that is needed is just a counter to indicate how many events one thread has processed, in Windows this is called a semaphore. Another thread can wait for this counter; if the counter is zero, this thread is just waiting and not executing any code. When the counter becomes non-zero, then that waiting thread will be started up by the operating system, and do whatever processing is required to deal with the completion of the event.
In other cases, a thread may need more information than just a counter, so instead of a counter, a queue of messages is used instead. The waiting thread retrieves a message, and peforms the required code for the specific message.
A simple example of a multi-threaded application would be data converter. There would be three threads, an input thread, a converter thread, and a output thread, and 4 pools of messages associated with buffers. The pools would be input-free-pool, input-filled-pool, output-free-pool, output-filled-pool. At start up, the free pools are created with some number of elements. The input thread waits for an element from the input-free-pool to become available (non-zero count), initiates and waits for data to be read, then sends the filled buffer to the input-filled-pool. The output thread waits for an output-filled-pool element, initiates and waits for the data to be written, then sends the empty buffer to the output-free-pool. The conversion thread, which should be lower priority, waits for an input-filled-pool element, and a output-free-pool element, does the data conversion from the input buffer to the output buffer, then sends the output buffer to the output-filled-pool, and returns the input buffer to the input-free-pool. The intertask messages would include a message that the end of the data (end of file) has been reached so that the threads can self terminate after passing the end of data message onto the next thread.
The coding for this data conversion application ends up allowing the data to be converted while the input and outputs are occurring at the same time. In addition, the buffering allows for the speed of the data to vary somewhat without stalling the entire process. It also simplfies the code in each thread as each thread just deals with one step.
In a game, you typicallly have a thread that receives user inputs, another thread that outputs graphics, and one or more threads to deal with the logic of the game itself.