according to 《0 be based on socket and pthread Implementation of multithreaded server model 》 Described ,server The following code is used to create a subthread :

 pconnsocke = (int *) malloc(sizeof(int));*pconnsocke = new_fd;
ret = pthread_create(&tid, NULL, rec_func, (void *) pconnsocke);if (ret < 0) 
{perror("pthread_create err");return -1;}


Get more about Linux Information , Please pay attention to the official account. 「 A bite of Linux」

Why do we have to malloc A block of memory is dedicated to this new socket ?
It takes some background knowledge to explain the cause of this problem :

  1. Linux When creating a new process , The new process creates a main thread ;
  2. Each user process has its own address space , The system creates one for each user process task_struct To describe the process ,
    actually task_struct It's used with the address table space to map , Represents a process ;
  3. Linux It's also used in the library task_struct To describe a thread , Threads and processes participate in unified scheduling ;
  4. Different threads in a process execute different parts of the same program , All threads execute in parallel , Asynchronous scheduling by the operating system ;
  5. Because the address space of the process is private , So when context switches between processes , The system overhead is relatively large ;
  6. Threads created in the same process share the address space of that process .

After understanding the basics , Let me take a look at , When a process creates a child thread , Parameters passed :

Pass the memory address in the stack directly

Let's first analyze that if you create a child thread and pass a local variable new_fd In this case .
 Insert picture description here
As shown in the figure above :

  1. Create a thread , If we follow the method of passing parameters in the graph , that new_fd It's in the stack , When creating sub threads, we put new_fd The address was delivered to thread1, Thread callback parameters arg The address is new_fd Address .

  2. Because the main function will loop all the time , therefore new_fd Always on the stack . In this way, you can really new_fd Value 3 Local variables passed to child threads fd, So the subthread can use this fd Communicating with clients .

  3. But because we're designing a concurrent server model , We have no way to predict when the client will connect to our server , Suppose you come across an extreme situation , At the same time , Multiple clients connect to the server at the same time , Then the main thread is to create multiple sub threads at the same time .

Multiple clients connect to the server at the same time
 Insert picture description here
As shown in the figure above , All the new ones thread The parameters of the callback function arg All the storage is new_fd The address of . If the time interval between client connections is relatively large , There is no problem , However, in some extreme cases, errors caused by high concurrency may still occur .

Let's take a look at the extreme call timing :

First step :

 Insert picture description here
As shown in the figure above :

  1. T1 moment , When the client 1 When connecting to the server , Server's accept Function creates a new socket 4;
  2. T2 moment , Created a child thread thread1, At the same time, the subthread calls back the function parameters arg Point to the stack new_fd Corresponding memory .
  3. hypothesis , Is this time , There's another client to connect to the server , and thread1 Page has run out of time , So the main thread server Will be dispatched to .

The second step :

 Insert picture description here
As shown in the figure above :
5. T3 moment , The main thread server Accepted the connection from the client ,accept Function creates a new socket 5, Create child threads at the same time thread2, here OS The scheduling of thread2;
6. T4 moment ,thread2 adopt arg obtain new_fd It's a good value 5, And deposit in fd;
7. T5 moment , Time is up , Dispatch thread1,thread1 adopt arg Read out new_fd, At this point in the stack new_fd The value of has been fixed 5 covers ;
8. So it's here 2 Two threads use the same fd What happened .

This happens , Although the probability is very low , But it doesn't mean it doesn't happen , The bug It's a problem that yikoujun encountered in solving the actual project .

Pass heap memory address

If you pass the address of the heap , Let's look at the picture below :

 Insert picture description here

  1. T1 moment , When the client 1 When connecting to the server , Server's accept Function creates a new socket 4, Request a block of memory in the heap , With a pointer pconnsocke Points to this memory , At the same time 4 Save to the heap ;
  2. T2 moment , Created a child thread thread1, At the same time, the subthread calls back the function parameters arg Point to the heap pconnsocke Memory pointed to .
  3. hypothesis , Is this time , There's another client to connect to the server , and thread1 Page has run out of time , So the main thread server Will be dispatched to .
  4. T3 moment , The main thread server Accepted the connection from the client ,accept Function creates a new socket 5, Request a block of memory in the heap , With a pointer pconnsocke Points to this memory , At the same time 5 Save to the heap , Then create a child thread thread2;
  5. T4 moment ,thread2 adopt arg Point to the heap pconnsocke Memory pointed to , The value of 5, And deposit in fd;
  6. T5 moment , Time is up , Dispatch thread1,thread1 adopt arg Read out fd, At this point, the data bits in the heap 5;
  7. There won't be 2 Two threads use the same fd What happened .

This knowledge point is a little hidden , I hope readers will be more careful when using it .
Next chapter , We will explain how to use our existing code to realize the function of login and registration .