Синхронизация потоков с помощью Mutex - PullRequest
0 голосов
/ 15 декабря 2018

Я пытаюсь понять понимание мьютексных замков.Я решаю математическое уравнение (a+b) * (c+d) / e, используя три различных потока, а именно сложение, умножение и деление.Для начала я написал этот код.Я имел в виду, что поток дополнения должен запускаться первым, а все остальные потоки должны быть заблокированы, но он дает случайный вывод.Вот код, который я написал до сих пор.

#include <iostream>
#include <pthread.h>

using std::cout, std::endl;

pthread_mutex_t mutex1;

void *Division(void *arg_div)
{
    int *input =(int *)arg_div;
    int result = input[0]/input[1];
    cout<<"Final result"<<endl;
    cout << result ;
    pthread_exit(NULL);
}

void *Multiplication(void *arg_mul)
{
    int *input =(int *)arg_mul;

    int arg1[2];
    arg1[0]=input[0]*input[1];
    arg1[1]=input[2];

    cout<<"Multiplication results are"<<endl;
    cout<<arg1[0];
    cout<<arg1[1];

    pthread_exit(NULL);
}

void *Addition(void *arg_add)
{
    pthread_mutex_lock(&mutex1);

    cout<<"Addition Thread is acquring lock"<<endl;

    int *input =(int *)arg_add;

    //my critical section
    int arg[3];
    arg[0]=input[0]+input[1];
    arg[1]=input[2]+input[3];

    pthread_mutex_unlock(&mutex1);

    arg[2]=input[4];

    cout<<"output of add function"<<endl;
    cout<<arg[0]<<endl;
    cout<<arg[1]<<endl;
    cout<<arg[2]<<endl;

    pthread_exit(NULL);
}

int main()
{
    int values[5]={6,5,4,3,2};

    pthread_t add;
    pthread_t multiply;
    pthread_t divide;

    pthread_create(&add,NULL,Addition,(void*)values);
    pthread_create(&multiply,NULL,Multiplication,(void*)values);
    pthread_create(&divide,NULL,Division,(void*)values);


    pthread_join(add,NULL);
    pthread_join(multiply,NULL);
    pthread_join(divide,NULL);


    return 0;
}

Я хочу, чтобы сначала выполнялся только дополнительный поток, затем поток умножения, а затем, наконец, деление.

Ответы [ 3 ]

0 голосов
/ 16 декабря 2018

Вот версия, использующая std::thread и переменные условия вместо использования интерфейса C для pthread.

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using std::cout, std::endl;

std::mutex m;
std::condition_variable cv_div_done, cv_mul_done, cv_add_done;

// these boolean variables are needed to detect Spurious wakeups
bool b_div_done=false, b_mul_done=false, b_add_done=false;

void Division(int *input) {
    std::unique_lock lk(m); // acquire mutex lock
    // wait() releases the lock until the condition is met
    // and here we wait for Multiplication to be done:
    cv_mul_done.wait(lk, []{ return b_mul_done; });
    // here we have the mutex lock again

    input[0] = input[0]/input[1];
    cout<<"Final result"<<endl;
    cout << input[0] << "\n";

    // signal those waiting for div to be done
    b_div_done = true;
    cv_div_done.notify_all();
} // lock released automatically when it goes out of scope

void Multiplication(int *input) {
    std::unique_lock lk(m);
    cv_add_done.wait(lk, []{ return b_add_done; });

    input[0]=input[0]*input[1];
    input[1]=input[2];

    cout<<"Multiplication results are"<<endl;
    cout << input[0] << "\n";
    cout << input[1] << "\n";

    b_mul_done = true;
    cv_mul_done.notify_all();
}

void Addition(int *input) {
    std::unique_lock lk(m); // not really needed in this case

    input[0]=input[0]+input[1];
    input[1]=input[2]+input[3];
    input[2]=input[4];

    cout<<"output of add function"<<endl;
    cout<<input[0]<<endl;
    cout<<input[1]<<endl;
    cout<<input[2]<<endl;

    b_add_done = true;
    cv_add_done.notify_all();
}

int main() { //  (a+b) x (c+d) / e
    int values[5]={6,5,4,3,2};

    std::thread add(Addition, values);
    std::thread mul(Multiplication, values);
    std::thread div(Division, values);

    /* if you'd like to run the threads detached (to not have to join them),
     * you can wait for the final result here */
    /*
    std::unique_lock lk(m);
    cv_div_done.wait(lk, []{ return b_div_done; });
    */

    add.join();
    mul.join();
    div.join();
}

Вывод:

output of add function
11
7
2
Multiplication results are
77
2
Final result
38
0 голосов
/ 16 декабря 2018

Для вычисления (a + b) x (c + d) / e сначала необходимо выполнить сложение, затем умножение и, наконец, деление.

Пусть у нас будет три семафора: sem-add с начальным значением 1, а также sem-multiply и sem-div, оба с начальным значением 0.

Код для трех арифметических функций должен быть,

addition () 
{
     P (sem-add);
     ...
     ...
     V (sem-multiply);
}

multiply ()
{
    P (sem-multiply);
    ....
    ....
    V (sem-divide);
}

division ()
{
    P (sem-divide);
    ....
    ....
    V (sem-add);
}

Подробнее см. Основы семафора

0 голосов
/ 15 декабря 2018

В вашем коде две проблемы.

1) Только один поток использует блокировку.Это не влияет на другие потоки, которые могут быть запущены в любое время.

2) Мьютекс предназначен для взаимного исключения, а не последовательности выполнения.Если вы хотите, чтобы один поток выполнялся раньше другого, вам нужно найти способ, чтобы это произошло.Например, «поток 2» может ожидать условие «поток 1» завершен;«поток 1» будет сигнализировать это условие соответствующим образом.Или вы можете взглянуть на модель использования семафора производителем / потребителем: поток сложения выдает результаты для потока умножения.

...