Advanced properties of thread control -- Realization of functions such as mutex and lock

Keywords: Attribute less

Content:
1. What is one-time initialization?


Example 1: one time initialization verification of pthread ﹣ once function:

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"

pthread_once_t once = PTHREAD_ONCE_INIT;//Declare global variables to ensure that they are executed once in this process
pthread_t tid;//Global thread id variable
//You can initialize the mutex, read-write lock in this function
//There is no initialization here, just print which thread called it
void init_routine()
{
    printf("init_routine used by thread 0x%ld\n",tid);
}
 //Thread 1
void *pthread_fun1(void *arg)
{
    tid = pthread_self();//Get your tid
    printf("this is thread1 0x%ld\n",tid);
    printf("once 1 is %ld\n",once);
    pthread_once(&once,init_routine);//Call initialization function
    printf("once 1 is %ld\n",once);
    
    sleep(1);   
    return (void*)1;
}
 
void *pthread_fun2(void *arg)
{
    sleep(2);
    tid = pthread_self();//Get your tid
    printf("this is thread2 0x%ld\n",tid);
    printf("once 2 is %ld\n",once);
    pthread_once(&once,init_routine);//Call initialization function
    printf("once 2 is %ld\n",once);
    
    sleep(1);   
    return (void*)2;
}
 
int main()
{

    pthread_t tid1,tid2;
    int errno1,errno2;
    int jval_1,jval_2;
    int *rval_1,*rval_2;
    
    errno1=pthread_create(&tid1,NULL,pthread_fun1,NULL);
    if(errno1 !=0)
    {
        printf("create new thread1 failure\n");
        return errno1;
     }
     
     errno2=pthread_create(&tid2,NULL,pthread_fun2,NULL);
     if(errno2 !=0)
     {
        printf("create new thread2 failure\n");
        return errno2;
     }
    
    sleep(1);
    jval_1=pthread_join(tid,&rval_1);//Wait for new thread 1 execution to complete 1
    sleep(1);
    jval_2=pthread_join(tid,&rval_2);//Wait for new thread 2 execution to complete
 
    sleep(2);   
    printf("jval_1=%d\n",jval_1);//Function return value of connection thread 1
    printf("jval_2=%d\n",jval_2);//Function return value of connection thread 2
    printf("rval_1=%d\n",(int*)rval_1);//Return value of thread 1
    printf("rval_2=%d\n",(int*)rval_2);//Return value of thread 2
        
    return 0;
}

The operation results are as follows:
1) When the once control value is pthread once init

As shown in the result, in the new thread 1, the pthread ﹣ once() function calls the initialization function init ﹣ routine(). When init ﹣ routine() is called by thread1 with a value of 0 and a value of 2 after it is called by thread1, the value of once becomes 2, which means that it can no longer be called by other threads (the function of one-time initialization); then when thread 2 calls the pthread ﹣ once function, when the value of once is 2, it can no longer call the initial function Initialize the init routine function to initialize its thread.
2) When the once control value is 1,

Threads thread1 and thread2 with pthread ﹣ once function are stuck in a permanent wait and cannot execute init ﹣ routine function.
2. Thread properties
Several properties of thread

1) Thread property initialization and destruction

2) Detach attribute
Separation at the end of the thread will release the resource space occupied by memory, and non separation will generate zombie thread.

Use of detached attributes

Example 2: application example of separation attribute

Create thread? Attr? Detache. C; as follows

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"

 //Thread 1
void *pthread_fun1(void *arg)
{
    printf("this is thread1 0x%ld\n",pthread_self());
    return (void*)1;
}
 
void *pthread_fun2(void *arg)
{
    printf("this is thread2 0x%ld\n",pthread_self());
    return (void*)2;
}
 
int main()
{

    pthread_t tid1,tid2;
    int errno1,errno2;
    int jval_1,jval_2;
    int *rval_1,*rval_2;
    pthread_attr_t attr;//Declare property object
    pthread_attr_init(&attr);//Initialize properties
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//set a property
    
    errno1=pthread_create(&tid1,&attr,pthread_fun1,NULL);
    if(errno1 !=0)
    {
        printf("create new thread1 failure\n");
        return errno1;
     }
     
     errno2=pthread_create(&tid2,NULL,pthread_fun2,NULL);
     if(errno2 !=0)
     {
        printf("create new thread2 failure\n");
        return errno2;
     }
    
    jval_1=pthread_join(tid1,&rval_1);//Wait for new thread 1 execution to complete 1
    jval_2=pthread_join(tid2,&rval_2);//Wait for new thread 2 execution to complete
 
    printf("jval_1=%d\n",jval_1);//Function return value of connection thread 1
    printf("jval_2=%d\n",jval_2);//Function return value of connection thread 2
    printf("rval_1=%d\n",(int*)rval_1);//Return value of thread 1
    printf("rval_2=%d\n",(int*)rval_2);//Return value of thread 2
    
   pthread_attr_destroy(&attr);     //Destroy attribute
    return 0;
}

When the thread attribute attr is set to DETACHED, the thread cannot be connected. For example, the attribute of thread tread1 is set to DETACHED. At this time, the main thread cannot establish a connection with it. The default property of thread 2 is NULL, that is, it is in a non DETACHED state. The running result is as follows:

When the property is set to JOINABLE, it is non detached and can be connected successfully. The operation result is as follows:

You can use the pthread ﹣ attr ﹣ gettachstate() function to get the detached state of its thread; this function is called in the main thread.
3) Stack properties
Stack size and address of thread (command to view stack size: ulimit -s)

Forbidden area at the end of the stack

Stack attribute instance: obtain and set the size of stack attribute;

Create thread_attr_setstack.c; as follows

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"

pthread_attr_t attr;
void *pthread_fun(void *arg)
{
size_t stacksize;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
        pthread_attr_getstacksize(&attr,&stacksize);
#endif 
    printf("this thread stack size is %ld\n",stacksize);
    return (void*)2;
}
 
int main()
{

    pthread_t tid;
    int errno;
    int jval;
    int *rval;
   
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
        pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
#endif
    
    errno=pthread_create(&tid,&attr,pthread_fun,NULL);
    if(errno !=0)
    {
        printf("create new thread1 failure\n");
        return errno;
     }
     
    
    jval=pthread_join(tid,&rval);//Wait for new thread execution to complete
 
    printf("jval=%d\n",jval);//Function return value of connection thread 1
    printf("rval=%d\n",(int*)rval);//Return value of thread 2
 
    pthread_attr_destroy(&attr);    
    return 0;
}


  • The above code sets the stack size to the system's default minimum pthread ﹣ stack ﹣ min through pthread ﹣ attr ﹣ setstacksize. The operation results are as follows:


As shown in the result, the default minimum value is 16384

When we don't use pthread_attr_setstacksize to set its size, its default value is the maximum value; we can also set the stack size ourselves, but it can't be less than its default minimum value, otherwise it will fail to set, and when it fails, the system will automatically default to the maximum value; for example, we set it to 5000, and modify it as follows:

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"

pthread_attr_t attr;
void *pthread_fun(void *arg)
{
size_t stacksize;
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
        pthread_attr_getstacksize(&attr,&stacksize);
        printf("first this thread stack size is %ld\n",stacksize);
        pthread_attr_setstacksize(&attr,5000);
#endif 
    printf("first this thread stack size is %ld\n",stacksize);
    return (void*)2;
}
 
int main()
{

    pthread_t tid;
    int errno;
    int jval;
    int *rval;
   
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
        //pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN);
#endif
    
    errno=pthread_create(&tid,&attr,pthread_fun,NULL);
    if(errno !=0)
    {
        printf("create new thread1 failure\n");
        return errno;
     }
     
    
    jval=pthread_join(tid,&rval);//Wait for new thread execution to complete
 
    printf("jval=%d\n",jval);//Function return value of connection thread 1
    printf("rval=%d\n",(int*)rval);//Return value of thread 2
 
    pthread_attr_destroy(&attr);    
    return 0;
}

The results are as follows:

2. Synchronization property of thread
1) Properties of mutex

1. Process sharing properties

2. Type attribute

3. Mutex attribute instance
Set the mutual exclusion property as the process sharing property to realize the process synchronization;

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"
#include"signal.h"
#include"sys/shm.h"

int main()
{
    char *shm="myshm";
    char *shm1="myshm1";
    int shm_id,shm_id1;
    char *buf;
    pid_t pid;
    
    //Open shared memory
    shm_id=shmget(IPC_PRIVATE,128,0777);
    if(shm_id<0) 
        {
         printf("create shared memory failure\n");
         return -1;
        }
    //Print shared memory
    buf =(char*)shmat(shm_id,NULL,0);
    if(buf==NULL) 
        { 
        printf("reflect the shared memory failure\n"); 
        return -2;
         }

    pthread_mutex_t *mutex;
    pthread_mutexattr_t mutexattr;

     //Open shared memory again
    shm_id1=shmget(IPC_PRIVATE,128,0777);
    if(shm_id1<0)
        {
         printf("second create shared memory failure \n");
         return -1;
        }
    //Print shared memory
    mutex =(char*)shmat(shm_id,NULL,0);
    if(mutex==NULL)
        {
        printf("reflect the shared memory to mutex failure\n");
        return -2;
        }
   pthread_mutexattr_init(&mutexattr);
#ifdef _POSIX_THREAD_PROCESS_SHARED
        pthread_mutexattr_setphared(&mutexattr,PTHREAD_PROCESS_SHARED);
#endif
        pthread_mutex_init(mutex,&mutexattr);

    pid=fork();
    if(pid==0)
    {
    //Sleep 1S, recognize the cpu to run the parent process first
    sleep(1);
    printf("I'm child proccess\n");
    
     pthread_mutex_lock(mutex);
    //Change the memory of shared memory to hello
    memcpy(buf,"hello",6);
    printf("child buf is :%s\n",buf);
     pthread_mutex_unlock(mutex);
    }
    
    if(pid>0)
    {
    printf("I'm parent process\n");
    
    pthread_mutex_lock(mutex);
    //Change the content of shared memory to world
    memcpy(buf,"world",6);
    sleep(3);
    printf("parent buf is :%s\n",buf);
    pthread_mutex_unlock(mutex);
    }
   pthread_mutexattr_destroy(&mutexattr);
    pthread_mutex_destroy(mutex);
    //Relieving printing
    shmdt(buf);
    //Eliminate shared memory
    shmctl(shm_id,IPC_RMID,NULL);
     //
        shmdctl(shm_id1);
    return 0;
   }

   

2) Read write lock properties

3) Properties of conditional variables

4. Thread private data

5. Threads and fork. How to use fork safely in threads?
Threads and fork

Example 1: you need to be a Ling person to clear the bell

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"
#include"signal.h"
#include"sys/shm.h"
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

void *pthread_fun(void *arg)
{
    sleep(1);//Sleep recognizes CPU to main thread
    pid_t pid;
    pid=fork();//Create child process in new thread
    if(pid==0)
    {
        //It is not successful to lock the mutex in the subprocess, because the mutex has been locked by the main process
        //It has not been unlocked by the main process. The subprocess cannot be unlocked. The subprocess stays here
        //Will not be able to proceed.
        pthread_mutex_lock(&mutex);
        printf("child\n");
        pthread_mutex_unlock(&mutex);
    }
    if(pid>0)
    {   //When the main thread sleeps for 2 seconds, the main process can be locked after unlocking.
        pthread_mutex_lock(&mutex);
        printf("parent\n");
        pthread_mutex_unlock(&mutex);
    }
 }
 
 int main()
 {
    pthread_t tid;
    int ret;
    ret=pthread_create(&tid,NULL,pthread_fun,NULL);
    if(ret!=0)
    {
        printf("create new thread failure\n");
        return -1;
    }
    //Lock mutex in main thread
    pthread_mutex_lock(&mutex);
    sleep(2);//Sleep for 2 seconds, let the new thread execute
    pthread_mutex_unlock(&mutex);
    printf("main\n");
    pthread_join(tid,NULL);
    
    return 0;
 }

The operation results are as follows:

Because the sub process of fork is a copy of the main process, there is a mutual exclusion locked by the main process in the copy, the sub process cannot be unlocked, and the "child" in the fruit process cannot be printed.
If you unlock the fork() subprocess before it can be locked and unlocked, the result is as follows.

Furthermore, lock the fork in the child thread, as follows:

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"
#include"signal.h"
#include"sys/shm.h"
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

void *pthread_fun(void *arg)
{
    sleep(1);//Sleep recognizes CPU to main thread
    pid_t pid;
    pthread_mutex_lock(&mutex);
    pid=fork();
    if(pid==0)
    {
        pthread_mutex_unlock(&mutex);
        printf("child\n");
    }
    if(pid>0)
    {
        pthread_mutex_unlock(&mutex);
        printf("parent\n");
        sleep(1);
    }
 }
 
 int main()
 {
    pthread_t tid;
    int ret;
    ret=pthread_create(&tid,NULL,pthread_fun,NULL);
    if(ret!=0)
    {
        printf("create new thread failure\n");
        return -1;
    }
    
    printf("main\n");
    pthread_join(tid,NULL);
    
    return 0;
 }

In this way, when the sub thread is in fork, it will also fork in pthread ﹐ mutex ﹐ lock (& mutext);
The fruiting process can be unlocked. The results are as follows:

Example: safe use of fork, call atfork function to unlock;

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
#include"limits.h"
#include"signal.h"
#include"sys/shm.h"
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void prepare()
{
        pthread_mutex_lock(&mutex);
        printf("I'm prepare\n");
}
void parent()
{
        pthread_mutex_unlock(&mutex);
        printf("I'm parent\n");
        sleep(1);
}
void child()
{
        pthread_mutex_unlock(&mutex);
        printf("I'm child\n");
}

void *pthread_fun(void *arg)
{
    sleep(1);//Sleep recognizes CPU to main thread
    pid_t pid;
    pthread_atfork(prepare,parent,child);
    pid=fork();
    if(pid==0)
    {
        pthread_mutex_lock(&mutex);
        printf("child process\n");
        pthread_mutex_unlock(&mutex);
    }
    if(pid>0)
    {
        pthread_mutex_lock(&mutex);
        printf("parent process\n");
        pthread_mutex_unlock(&mutex);
    }
 }
 
 int main()
 {
    pthread_t tid;
    int ret;
    ret=pthread_create(&tid,NULL,pthread_fun,NULL);
    if(ret!=0)
    {
        printf("create new thread failure\n");
        return -1;
    }
    
    pthread_mutex_lock(&mutex);
    sleep(2);
    pthread_mutex_unlock(&mutex);
    printf("main\n");
    pthread_join(tid,NULL);
    
    return 0;
 }

The operation results are as follows:

Before running fork, the prepare function is called to lock. Fork returns the main process before calling parent to unlock and calls child to unlock before fork returns to the sub process.

Finally, multithreading summary

Published 34 original articles, won praise 12, visited 1447
Private letter follow

Posted by srdva59 on Fri, 17 Jan 2020 05:01:52 -0800