Linux system programming - (pthread) thread communication (spin lock)

Posted by jasonok6 on Tue, 25 Jan 2022 09:30:50 +0100

1. Introduction to spin lock

Spin lock will be used in both kernel programming and application layer programming; Spinlock is similar to mutex. Instead of blocking the process through sleep, it is always in a busy state (also known as spin) before obtaining the lock.

Spin locks can be used when the lock is held for a short time and the thread does not want to spend too much cost on rescheduling. Spin locks are often used as underlying primitives to implement other types of locks. According to the system architecture they are based on, they can be effectively implemented by using tests and setting instructions. Of course, the effectiveness mentioned here will also lead to a waste of CPU resources: when the thread spin lock becomes available, the CPU can't do anything else, which is why the spin lock can only be used for a short period of time.

Spin lock summary:

  1. The use framework and scenario of spin lock and mutex lock are similar.

  2. Mutexes sleep when they can't get a lock.

  3. The spin lock will not sleep when it cannot get the lock, and will always detect the state of the lock.

  4. Spin lock is more suitable for protection variable assignment, function call and other scenarios.

2. Spin lock related interface functions

1. Destroy spin lock
int   pthread_spin_destroy(pthread_spinlock_t *);
2. Initialize spin lock
int   pthread_spin_init(pthread_spinlock_t *, int);
3. Spin lock(block)
int   pthread_spin_lock(pthread_spinlock_t *);
4. Spin lock(Non blocking)
int   pthread_spin_trylock(pthread_spinlock_t *);
5. Spin lock unlock
int   pthread_spin_unlock(pthread_spinlock_t *);
The above functions return 0 successfully.

pthread_ spin_ The pshared parameter of init function represents the process sharing attribute, indicating how the spin lock is obtained if it is set to PTHREAD_PROCESS_SHARED, the spin lock can be acquired by threads that can access the underlying memory of the lock, even if those threads belong to different processes. Otherwise, the pshared parameter is set to PTHREAD_PROCESS_PRIVATE, the spin lock can only be accessed by the thread inside the process initializing the lock.

If the spin lock is currently unlocked, pthread_ spin_ The lock function can lock the spin lock without spin. It attempts to unlock the spin lock without lock. The result is undefined. It should be noted that functions that may enter the sleep state when holding the spin lock are not allowed. If these functions are called, CPU resources will be wasted, and other threads need to wait longer to obtain the spin lock.

3. Spin lock application template

The following code creates two threads to access a global variable respectively, which is protected by spin lock.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>

pthread_spinlock_t spinlock;

int data;
/*
Thread work function
*/
void *thread_work_func(void *dev)
{
    while(1)
    {
        pthread_spin_lock(&spinlock); //Lock
        printf("data=%d\n",data);
        pthread_spin_unlock(&spinlock); //Unlock
        sleep(1);
    }
}

/*
Thread work function
*/
void *thread_work_func2(void *dev)
{
    while(1)
    {
        pthread_spin_lock(&spinlock); //Lock
        data++;
        pthread_spin_unlock(&spinlock); //Unlock
        sleep(1);
    }
}

int main(int argc,char **argv)
{   
    //Initialize spin lock
    pthread_spin_init(&spinlock,PTHREAD_PROCESS_PRIVATE);

    /*1. Create child thread 1*/
    pthread_t thread_id;
    if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
    {
        printf("Creation of child thread 1 failed.\n");
        return -1;
    }
    /*2. Create child thread 2*/
    pthread_t thread_id2;
    if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0)
    {
        printf("Child thread 2 creation failed.\n");
        return -1;
    }

    /*3. Introduction to waiting thread*/
    pthread_join(thread_id,NULL);
    pthread_join(thread_id2,NULL);

    //Destroy spin lock
    pthread_spin_destroy(&spinlock);
    return 0;
}

Topics: Linux Operation & Maintenance server