Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
1

Организовать работу функции так, чтобы программа не дожидалась окончания её выполнения (многопоточность)

24.12.2015, 13:11. Показов 1798. Ответов 20

Author24 — интернет-сервис помощи студентам
Всем привет. Только начинаю применять многопоточность. В нижеследующем коде нужно организовать таким образом, чтобы программа не дожидалась окончания функции LongFunc, а продолжала свою работу далее. Т.е. сейчас программа выводит только результат, а нужно чтобы пока результат не готов выводилось BlaBlaBla. Причём весь код для многопоточности нужно заключить внутрь класса A. Как бы это сделать?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
 
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
};
 
A::A()
{
    Status = 0;
    Result = 0;
}
 
void A::LongFunc()
{
    Status = -1;
    for (int i = 0; i < 1000000000; i++)
    {
        Result++;
    }
    Status = 1;
}
 
int A::GetStatus()
{
    return Status;
}
 
int A::GetResult()
{
    return Result;
}
 
int main(int argc, char** argv) 
{
    A a;
    while (1)
    {
        if (a.GetStatus() != -1)
        {
            printf("%d\r\n", a.GetResult());
            a.LongFunc();
        }
        else printf("BlaBlaBla\r\n");
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.12.2015, 13:11
Ответы с готовыми решениями:

<omp.h> Организовать работу рабочих так, чтобы они копали траншею одновременно
У нас есть траншея и два рабочих, которые копают траншею по очереди. Вот как это выглядит: ...

Организовать работу sms-сервиса так, чтобы познакомить каждого участника ровно с тем количеством других, сколько ему требуется
Ребят,помогите решить задачу!SMS сервис. Существует СМС сервис.Каждый участник заплатил за...

Изменить for на while, но так, чтобы программа оставалась прежней, то есть выполняла ту же работу
Нужна помощь в решении проблемы. Правда язык обучения у меня английский, поэтому некоторые задания...

Проверка окончания выполнения функции
В JS функции выполняются по порядку их вызова. Но JS абсолютно наплевать, завершилось ли выполнение...

20
Хитрая блондиночка $)
1472 / 988 / 399
Регистрация: 21.12.2015
Сообщений: 3,785
24.12.2015, 13:25 2
Ну внутрь класса не скажу, но вот поиск показывает следующее: Самый простой способ реализации двух параллельных потоков
0
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
24.12.2015, 13:39  [ТС] 3
Нет, нужно именно внутри класса, т.к. класс А будет выноситься в отдельную библиотеку и пользователю не нужно знать что там внутри происходит.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
24.12.2015, 15:50 4
C++
1
std::thread(&A::LongFunc, &a)
Но у Вас тут логика программы не позволит нормально использовать многопоточность.
0
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
24.12.2015, 15:56  [ТС] 5
Croessmah, почему не позволит и куда эту строку вставить?
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
24.12.2015, 16:02 6
Цитата Сообщение от APXAHGEL Посмотреть сообщение
почему не позволит
потому что, например, if (a.GetStatus() != -1) может выполнится еще пару раз, прежде чем в другом потоке выполнится Status = -1. Соответственно это приведет к запуску других потоков, а после того, как один из них поставит Status в единицу, получим еще запуск потоков, а потом завершится еще один поток и т.д. короче логика здесь явно не та. Лучше опишите что Вы хотите получить в результате.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.12.2015, 16:09 7
APXAHGEL, Ну можно как-то так...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
 
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    std::atomic<int> Status;
    int Result;
};
 
A::A()
{
    Status = 0;
    Result = 0;
}
 
void A::LongFunc()
{
    std::thread t([this]()
    {
       Status = -1;
       for (int i = 0; i < 1000000000; i++)
       {
          Result++;
       }
       Status = 1;
    });
    t.detach();
}
 
int A::GetStatus()
{
    return Status.load();
}
 
int A::GetResult()
{
    return Result;
}
 
int main(int argc, char** argv) 
{
    A a;
    while (a.GetStatus() != 1)
    {
        if (a.GetStatus() != -1)
        {
            printf("%d\r\n", a.GetResult());
            a.LongFunc();
        }
        else
        {
           printf("BlaBlaBla\r\n");
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
24.12.2015, 16:17 8
ForEveR, всё равно всё это как-то не так...
C++
1
2
3
4
5
6
7
8
    while (a.GetStatus() != 1)//проверили, Status еще в -1
    {
        //Другой поток поменял статус на 1
        if (a.GetStatus() != -1) //Тут уже true
        {
            printf("%d\r\n", a.GetResult());
            a.LongFunc();//Запускаем еще раз.
        }
Или я что-то недоглядел?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.12.2015, 16:22 9
Croessmah, А фиг его знает, я особо не вглядывался. По хорошему sleep на секунду вполне дает изменять статусы как надо. В идеале нужно сделать по другому конечно.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,737
Записей в блоге: 1
24.12.2015, 16:32 10
Цитата Сообщение от ForEveR Посмотреть сообщение
По хорошему sleep на секунду вполне дает изменять статусы как надо.
Оно даст задержку при запуске потока, чтобы Status успел в -1 поставиться, но между двумя теми проверками нет никакой защиты, так что между ними может вклиниться поток и поставить статус в 1.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.12.2015, 16:39 11
Croessmah, Тут по хорошему через future стоило бы делать.

Не по теме:

Но мне как-то лень этим сейчас заниматься.

0
Croessmah
24.12.2015, 16:40
  #12

Не по теме:

Цитата Сообщение от ForEveR Посмотреть сообщение
Но мне как-то лень этим сейчас заниматься.
угу :)

0
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
24.12.2015, 16:58  [ТС] 13
Croessmah, ForEveR, наверное я про логику всё же не дописал. В общем должно быть как-то так: В основном потоке есть какой-то цикл. В этом цикле мы запускаем функцию LongFunc, которая запускается в отдельном потоке и основной поток продолжает выполняться не ожидая завершения работы этой функции. Функция работает в единственном экземпляре. На следующей итерации цикла основного потока мы проверяем через GetStatus завершилась ли работа функции LongFunc и если да, то считываем её результат через GetResult, печатаем его на экране и запускаем функцию LongFunc ещё раз, если нет выполняем какие-то действия (в данном случае печатаем BlaBlaBla). В теле функции main ничего дописывать не надо, т.к. класс А позже станет библиотекой и тот, кто будет им пользоваться не будет знать о его внутреннем устройстве.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
24.12.2015, 17:46 14
APXAHGEL, Это не корректно.
C++
1
2
3
    while (1)
    {
        if (a.GetStatus() != -1)
Тут без каких-либо ухищрений запросто функция LongFunc вызовется дважды подряд. Только если проверять в LongFunc что она уже запущена.

Добавлено через 3 минуты
Как-то так можно. sleep в main добавлен чтобы не видеть миллионы строк.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <future>
#include <chrono>
 
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
 
    std::future<void> future;
};
 
A::A()
{
    Status = 0;
    Result = 0;
}
 
void A::LongFunc()
{
    Result = 0;
    Status = -1;
    future = std::async(std::launch::async, [this]()
    {
       for (int i = 0; i < 1000000000; i++)
       {
          Result++;
       }
    });
}
 
int A::GetStatus()
{
    if (Status == -1 && future.wait_for(std::chrono::microseconds(1)) == std::future_status::ready)
    {
       future.get();
       Status = 1;
    }
    return Status;
}
 
int A::GetResult()
{
    return Result;
}
 
int main(int argc, char** argv) 
{
    A a;
    while (1)
    {
        if (a.GetStatus() != -1)
        {
            printf("%d\r\n", a.GetResult());
            a.LongFunc();
        }
        else 
        {
           printf("BlaBlaBla\r\n");
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}
В идеале, чтобы future возвращала int, а GetResult делал wait/get.

Добавлено через 9 минут
Хотя через thread будет попроще.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <stdio.h>
#include <thread>
 
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
};
 
A::A()
{
    Status = 0;
    Result = 0;
}
 
void A::LongFunc()
{
    Result = 0;
    Status = -1;
    std::thread t([this]()
    {
       for (int i = 0; i < 1000000000; i++)
       {
          Result++;
       }
       Status = 1;
    });
    t.detach();
}
 
int A::GetStatus()
{
    return Status;
}
 
int A::GetResult()
{
    return Result;
}
 
int main(int argc, char** argv) 
{
    A a;
    while (1)
    {
        if (a.GetStatus() != -1)
        {
            printf("%d\r\n", a.GetResult());
            a.LongFunc();
        }
        else 
        {
           printf("BlaBlaBla\r\n");
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}
1
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
25.12.2015, 13:39  [ТС] 15
ForEveR, Спасибо огромное за последний код, только вот хочу ещё уточнить, в GetStatus не нужно ли добавить каких синхронизаций/блокировок или ещё чего. И ещё, как нужно модифицировать код, чтобы из main при вызове LongFunc можно было передать в него параметры, ну к примеру так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char** argv) 
{
    A a;
    int Multiplier = 1;
    unsigned int Array[] = {1,2,3,4,5};
    while (1)
    {
        if (a.GetStatus() != -1)
        {
            printf("%d\r\n", a.GetResult());
            std::this_thread::sleep_for(std::chrono::seconds(1));
            a.LongFunc(Array, Multiplier);
            Multiplier++;
        }
        else 
        {
           printf("BlaBlaBla\r\n");
        }
    }
}
Добавлено через 2 часа 13 минут
С передачей параметров разобрался, нужно просто вместо std::thread t([this]() написать std::thread t([this, Array, Multiplier](). Но всё-таки хочется узнать насчёт GetStatus и ещё такой момент, я как понимаю при каждом входе в функцию идёт новое создание потока, что выполняется достаточно долго. Можно ли, допустим, создать поток один раз в конструкторе класса и использовать его всё время?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
25.12.2015, 13:53 16
APXAHGEL, Каких синхронизаций/блокировок в функцию которая только возвращает статус?
Да, каждый раз идет создание потока. Можно создать в конструкторе конечно, но надо ведь дать потоку понять что пора работать/пора спать.

Добавлено через 10 минут
Можно что-нибудь типа такого.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
    bool Run;
 
    std::thread thread;
};
 
A::A() : Status(0), Result(0), Run(false)
{
    thread = std::thread([this]()
    {
       while (true)
       {
         if (!Run) continue;
         for (int i = 0; i < 1000000000; i++)
         {
            Result++;
         }
         Status = 1;
         Run = false;
       }
    });
    thread.detach();
}
 
void A::LongFunc()
{
    Result = 0;
    Status = -1;
    Run = true;
}
0
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
25.12.2015, 13:58  [ТС] 17
ForEveR, я в многопоточности новичок, поэтому вопрос может быть глупым, но не может ли случиться ситуация, когда мы запрашиваем GetStatus из основного потока (в функции main) и одновременно с этим Status изменяется в другом потоки. Это вроде как состояние гонки называется и вроде Status тогда может вернуться вообще левым числом каким-то.
Цитата Сообщение от ForEveR Посмотреть сообщение
Можно создать в конструкторе конечно
Это как выглядеть будет?
Цитата Сообщение от ForEveR Посмотреть сообщение
надо ведь дать потоку понять что пора работать/пора спать
По вызову LongFunc передавать в него параметры и запускать и чтобы останавливался по окончании работы.
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
25.12.2015, 14:10 18
APXAHGEL, Не должно тут возникнуть гонки по хорошему. А на тему примера - выше.
0
6 / 6 / 0
Регистрация: 13.07.2013
Сообщений: 57
25.12.2015, 15:08  [ТС] 19
ForEveR, но в таком случае вспомогательный поток не будет усыпляться. Там постоянно будет вызываться if (!Run) continue;. Можно ли как-то его усыпить, чтобы он вообще не тратил процессорного времени? Условные переменные не из той оперы?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
25.12.2015, 15:46 20
Лучший ответ Сообщение было отмечено APXAHGEL как решение

Решение

APXAHGEL, Ну можно сделать через condition_variable.wait.

Добавлено через 16 минут
Что-то вроде

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
    bool Run;
 
    std::thread thread;
    std::condition_variable cond;
};
 
A::A() : Status(0), Result(0), Run(false)
{
    thread = std::thread([this]()
    {
       std::mutex mutex;
       while (true)
       {
          std::unique_lock<std::mutex> lock(mutex);
          cond.wait(lock, [this]() { return Run; });
          for (int i = 0; i < 1000000000; i++)
          {
             Result++;
          }
          Status = 1;
          Run = false;
       }
    });
    thread.detach();
}
 
void A::LongFunc()
{
    Result = 0;
    Status = -1;
    Run = true;
    cond.notify_one();
}
А лучше так с мьютексом.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class A
{
public:
    A();
    void LongFunc();
    int GetStatus();
    int GetResult();
private:
    int Status;
    int Result;
    bool Run;
 
    std::thread thread;
    std::mutex mutex;
    std::condition_variable cond;
};
 
A::A() : Status(0), Result(0), Run(false)
{
    thread = std::thread([this]()
    {
       while (true)
       {
          std::unique_lock<std::mutex> lock(mutex);
          cond.wait(lock, [this]() { return Run; });
          for (int i = 0; i < 1000000000; i++)
          {
             Result++;
          }
          Status = 1;
          Run = false;
       }
    });
    thread.detach();
}
 
void A::LongFunc()
{
    {
    std::unique_lock<std::mutex> lock(mutex);
    Result = 0;
    Status = -1;
    Run = true;
    }
    cond.notify_one();
}
0
25.12.2015, 15:46
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.12.2015, 15:46
Помогаю со студенческими работами здесь

Нужно сделать так чтобы при неправильном вводе программа не прекращала работу, а предлагала заново ввести значение N
Вот собственно сам код #include&lt;ctime&gt; #include&lt;iostream&gt; using namespace std; int N,...

Программа не прекращает работу при выполнении условия окончания
Здравствуйте! есть функция void Bred::find2() { static bool trigger; char a, b; a =...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru