Based on the multithreading implementation of Linux C language, find the number of prime numbers from 30000000 to 30001000 (four threads as an example)

Keywords: C C++ Mini Program

1, Procedural thought

        Threads are characterized by independence, concurrency, and threads share memory. Think of the main function as a main thread. The work of the main thread is to allocate the number from 30000000, and the four sub threads grab the number from the main thread. This requires an intermediate variable, condition variable cond and mutex.

         Imagine that there is an intermediate value between the main thread and the four sub threads. When the main thread allocates the number, the intermediate value is the number allocated by the main thread. At the same time, wake up the four sub threads to snatch the number. When a child thread grabs the number, it needs to remove the number in the middle value, set the middle value to 0, and tell the main thread that it can continue to allocate the next number to the middle value. The sub thread that gets the previous number will calculate this number, and the other three sub threads will continue to rob the main thread of the newly allocated number. After the sub thread operation of the previous number is completed, continue to wait for the number allocated by the main thread and rob the number. It can be seen that the work of the four sub threads is the same.

2, Thinking logic diagram

  3, Conditional variables and mutexes

        (1) Thread mutex: in multithreading, multiple tasks running at the same time may need to use the same resource. Mutex is a simple locking method to control access to shared resources. Mutex has only two states, lock and unlock. When a thread is locked, other threads cannot continue and will not occupy CPU resources. Only when this thread is unlocked can other threads continue.

        (2) Condition variables: unlike mutexes, condition variables are used to wait rather than lock. Conditional variables are used to automatically block a thread until a special situation occurs. Usually, conditional variables and mutexes are used at the same time. Conditional variables allow us to sleep and wait for certain conditions to occur. Condition variable is a mechanism for synchronization by using the global variables shared among threads, which mainly includes two actions: a thread waits for "the condition of condition variable is established" and hangs; Another thread makes the "condition true" (gives the condition true signal). Condition detection is carried out under the protection of mutex. If a condition is false, a thread automatically blocks and releases the mutex waiting for a state change. If another thread changes the condition, it sends a signal to the associated condition variable to wake up one or more threads waiting for it, regain the mutex and re evaluate the condition. If two processes share read-write memory, condition variables can be used to achieve thread synchronization between the two processes. Initialize the condition variable before using it. You can generate and initialize a condition variable in a single statement, such as pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER; (used for inter process thread communication). You can use the pthread function_ cond_ Init dynamic initialization.   Conditional variables are divided into two parts: conditions and variables. Conditions themselves are protected by mutexes. Threads must lock mutexes before changing the condition state. It uses a mechanism to synchronize global variables shared between threads.

4, Source code

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define L 30000000
#define R 30001000
#define N 4
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

struct data
{
    int data;
};

int isPrimer(int val)
{
    int i = 2;
    for(i =2 ;i< val/2 ; i++){
        if(0 == (val % 2)) {
            return 0;
        }
    }
    return val;
}
void *work(void *arg)
{
    struct data *d = (struct data *)arg;
    int val = 0;
    while(1) {
        pthread_mutex_lock(&mutex);
        if(d->data == 0) {
               pthread_cond_wait(&empty,&mutex);
        }
        val = d->data;
        if(val > R) {
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }
        d->data = 0;
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&full);
        if(isPrimer(val)) {
            printf("%d is Primer\n",val);
        }
    }
}
int main()
{
    int i = 0;
    pthread_t t[N];
    struct data d;
    d.data = 0;
    for(i = 0; i < N ;i++) {
        pthread_create(&t[i],NULL,work,&d);
    }  
    
    for(i=L;i<R+1;i++){
        pthread_mutex_lock(&mutex);
        if(d.data){
            pthread_cond_wait(&full,&mutex);
        }
        d.data = i;
        pthread_cond_broadcast(&empty);
        pthread_mutex_unlock(&mutex);
    }
    for(i = 0;i<N;i++) {
        pthread_join(t[i],NULL);
    }
    pthread_cond_destroy(&empty);
    pthread_cond_destroy(&full);
    pthread_mutex_destroy(&mutex);
    return 0;
}

5, Summary

        The emergence of multithreading speeds up the efficiency of program operation, and it is not difficult to find prime numbers. However, if they are written in the main function, only one can be calculated one by one, but multithreading can directly allocate numbers and let other threads calculate. It greatly speeds up the efficiency of program operation.

 

Posted by d22552000 on Thu, 07 Oct 2021 12:01:37 -0700