Original

Struct Memory Allocation with Pthreads in C


The most common way to implement memory allocation in C is to use malloc() d free().

Why do we allocate memory for structs?

  • A struct can be allocated automatically, but if we create a pointer to a struct, the creation will not allocate space for the destination struct.
  • We have to allocate memory for a struct, if we want to use this struct variable outside the function. Otherwise, the memory will be freed when the function ends.

The allocated memory should be freed. It is a very common mistake to forget to free the memory or mistakenly free the memory, especially when it is needed to perform multithreading tasks. We have to ensure that the memory will be allocated and freed at the right position (time) to avoid memory overflow and segmentation fault.

An example of a multi-threaded HTTP web server

Below is an example of a multi-threaded HTTP web server based on boss-worker thread pattern in C, using pthread library.

Worker threads woker_serve() will be initialized in the main function first. Then, after the main function calls the gfserver_serve() function, gfserver_serve() will loop forever to accept client requests and pass all received requests from the server socket into the "Boss" thread: gfs_handler. The Boss thread will store the requests (struct *task) into a task queue and signal the waiting worker threads to start reading tasks from the task queue to process the requests.

There are two pieces of allocated memory (ctx and t) that we have to free in this endless loop:

  • gfcontext_t is a struct that contains the information of a client socket.
  • task is a struct that contains the info of gfcontext_t and downloading path.

Here, we pass the ctx into the boss thread through a secondary pointer. This is because that the pointer pointing to ctx (i.e. &ctx) will be reused in gfserver_serve(), but the memory space that &ctx is pointing to now (i.e. ctx) has to be kept until the worker threads finish processing the info stored there. So we will let the pointer (&ctx) points to NULL first in the boss thread.

Since parameters in C are Pass-by-Value, any changes to the parameter have NO effect on data in the calling function. We cannot let &ctx in gfserver_serve() point to NULL in gfs_handler, if we simply pass the pointer &ctx into gfs_handler. We have to pass the address of the pointer.

Once the worker threads finished processing the info stored in gfcontext_t ctx which is passed into the worker thread through the struct task t, the memory of ctx (malloc A) should be freed. After that, the memory of t (malloc B) should be freed.

0
  • By Yuechun Wang
  • Published 2020-09-22
  • The materials on this website may be freely copied and distributed for noncommercial personal use only so long as our copyright notice and website address is included.
  • Comments