Тема: Потоки

Почав вчити потоки, але щось нічого не зрозуміло. У першому кроці викликаються два потоки одночасно (напевно), як мені зробити затримку у створеному потоці "pt"?  Ось цей метод (std::this_thread::sleep_for) виконується в main-і (на 5 мілісекунд).
А як мені його задіяти для "st"? Потрібно використовувати його в функції, чы яккк? Скоріш за все, я неправильно зрозумів щось підкажіть будь ласка.

#include <iostream>
#include <thread>
#include <string>

#include <chrono>
 
void print(int num,int pos) {

    if (pos == 1) {
        for (int i = 0; i < num; i++) {
            std::cout << "------------------ " << i << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(2));
        }
    }
    else {
        if (pos == 2) {
            for (int i = 0; i < num; i++) {
                std::cout << i - num + 1 << " ------------------" << std::endl;
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
        }
    }

}


int main(){

    setlocale(LC_ALL, "Ukr");
    int num = 5;
    std::thread pt(print, num,1);
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    print(num, 2);
    
    pt.detach();
    
    


    return 0;

}

Re: Потоки

if (pos == 1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        for (int i = 0; i < num; i++) {
            std::cout << "------------------ " << i << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(2));
        }
    }

Якщо вставити перед циклом в if, то працює, але як зробити main?

3 Востаннє редагувалося koala (12.01.2021 15:42:19)

Re: Потоки

Я не зовсім зрозумів, у чому саме проблема. Там є проблема з detach - має бути join, інакше програма завершується і вбиває потік, detach захищає від знищення об'єкту, але не всього процесу. Але всі затримки працюють, як належно.
Можете пояснити, що виводить у вас програма і на що ви очікували?

Re: Потоки

koala написав:

Я не зовсім зрозумів, у чому саме проблема. Там є проблема з detach - має бути join, інакше програма завершується і вбиває потік, detach захищає від знищення об'єкту, але не всього процесу. Але всі затримки працюють, як належно.
Можете пояснити, що виводить у вас програма і на що ви очікували?

А join або detach потрібно використовувати перед завершенням головного потоку?  Бо я пробував detach вставити в різні фрагменти коду, працює одинаково.join щось по-різному.

5

Re: Потоки

І join, і detach працюють однаково де завгодно, і їх треба використовувати там, де вам це потрібно. Не намагайтеся відгадати, що вони роблять - прочитайте, якщо незрозуміло - поекспериментуйте. І якщо надалі ігноруватимете мої питання - я вам нічим допомогти не зможу.

Re: Потоки

koala написав:

І join, і detach працюють однаково де завгодно, і їх треба використовувати там, де вам це потрібно. Не намагайтеся відгадати, що вони роблять - прочитайте, якщо незрозуміло - поекспериментуйте. І якщо надалі ігноруватимете мої питання - я вам нічим допомогти не зможу.

Перепрошую, не замітив. Могли б Ви глянути код? Потрібно вивести одночасно 2 рядочки тексту( черги та стеку) але я зміг вивести їх тільки вертикально... Не знаю як зробити горизонтально.

Ось код

#pragma once
#include <string>

class node {
   
    public:

        std::string name;
        std::string index;
        class node* nextnode;

        node* returnnewnode(std::string);
        std::string returnindex(std::string);
};

class line : public node {

    private:
        std::string** mass;
        int numqueue;
        int numstack;
        class node* queue;
        class node* stack;
        

    public:

        line();
        int returnnum(std::string);
        void name(std::string);
        void fullline(std::string);
        void print(std::string);
        void printmass(std::string);

};


#include "line.h"
#include <iostream>
#include <thread>
#include <chrono>


node* node::returnnewnode(std::string index) {

    class node* newnode = new node;
    newnode->index = index;
    newnode->nextnode = nullptr;
    return newnode;

}


std::string node::returnindex(std::string name) {
    
    std::cout << "Введіть індекс нового елементу ";
    if (name == "stack") {
        std::cout << "стеку: ";
        std::string index;
        std::cin >> index;
        return index;
    }
    else {
        if (name == "queue") {
            std::cout << "черги: ";
            std::string index;
            std::cin >> index;
            return index;
        }
    }

}


void line::name(std::string name) {

    if (name == "queue") {
        std::cout << "Введіть к-сть елементів черги: ";
        std::cin >> numqueue;
    }
    else {

        if (name == "stack") {
            std::cout << "Введіть к-сть елементів стеку: ";
            std::cin >> numstack;
        }
    }
    return;

}


void line::fullline(std::string name) {
    if (name == "queue") {
        if (queue == nullptr) {
            std::string index = node::returnindex(name);
            class node* newnode = node::returnnewnode(index);
            queue = newnode;
        }
        else {
            if (queue != nullptr) {
                class node* findlast = queue;
                while (findlast->nextnode != nullptr) {
                    findlast = findlast->nextnode;
                }
                std::string  index = node::returnindex(name);
                class node* newnode = node::returnnewnode(index);
                findlast->nextnode = newnode;
            }
        }
    }else {
        if (name == "stack") {
            if (stack == nullptr) {
                std::string  index = node::returnindex(name);
                class node* newnode = node::returnnewnode(index);
                stack = newnode;
            }
            else {
                if (stack != nullptr) {
                    std::string  index = node::returnindex(name);
                    class node* newnode = node::returnnewnode(index);
                    newnode->nextnode = stack;
                    stack = newnode;
                }
            }
        }
    }
    return;

}

void line::print(std::string name) {
    if (name == "queue") {
        class node* printline = queue;
        int i = 0;
        while (printline != nullptr) {
            if (printline->nextnode == nullptr) {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << printline->index;
                mass[i][1] = printline->index;
                i = i + 1;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << "-";
                mass[i][1] = "|";
                i = i + 1;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << ">";
                mass[i][1] = "+";
                i = i + 1;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << "nullptr";
                mass[i][1] = "n";
                i = i + 1;
                mass[i][1] = "u";
                i = i + 1;
                mass[i][1] = "l";
                i = i + 1;
                mass[i][1] = "l";
                i = i + 1;
                mass[i][1] = "p";
                i = i + 1;
                mass[i][1] = "t";
                i = i + 1;
                mass[i][1] = "r";
                i = i + 1;
                printline = printline->nextnode;
            }
            else {
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << printline->index;
                mass[i][1] = printline->index;
                i = i + 1;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << "-";
                mass[i][1] = "|";
                i = i + 1;
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                std::cout << ">";
                mass[i][1] = "+";
                i = i + 1;
                printline = printline->nextnode;
            }
            
        }
    }
    else {
        if (name == "stack") {
            int i = 0;
            class node* printline = stack;
            while (printline != nullptr) {
                if (printline->nextnode == nullptr) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << printline->index;
                    mass[i][0] = printline->index;
                    i = i + 1;
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << "-";
                    mass[i][0] = "|";
                    i = i + 1;
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << ">";
                    mass[i][0] = "+";
                    i = i + 1;
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << "nullptr";
                    mass[i][0] = "n";
                    i = i + 1;
                    mass[i][0] = "u";
                    i = i + 1;
                    mass[i][0] = "l";
                    i = i + 1;
                    mass[i][0] = "l";
                    i = i + 1;
                    mass[i][0] = "p";
                    i = i + 1;
                    mass[i][0] = "t";
                    i = i + 1;
                    mass[i][0] = "r";
                    i = i + 1;
                    printline = printline->nextnode;
                }
                else {
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << printline->index;
                    mass[i][0] = printline->index;
                    i = i + 1;
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << "-";
                    mass[i][0] = "|";
                    i = i + 1;
                    std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    std::cout << ">";
                    mass[i][0] = "+";
                    i = i + 1;
                    printline = printline->nextnode;
                }

            }
        }
    }
    return;

}


line::line() {

    mass = new std::string * [20];
    for (int i = 0; i < 20; i++) {
        mass[i] = new std::string[2];
        
    }
    
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 2; j++) {
            mass[i][j] = "99999";
        }
    }

}


int line::returnnum(std::string name) {
    
    if (name == "stack") {
        return numstack;
    }
    else {
        if (name == "queue") {
            return numqueue;
        }
    }
}


void line::printmass(std::string name) {

    if (name == "stack") {
        for (int j = 0; j < 20; j++) {
            if (mass[j][0] != "99999") {
                std::this_thread::sleep_for(std::chrono::seconds(1));
                std::cout << mass[j][0] << "   #" << std::endl;
            }
        }
    }
    else {
        if (name == "queue") {
            for (int j = 0; j < 20; j++) {
                if (mass[j][1] != "99999") {
                    std::this_thread::sleep_for(std::chrono::milliseconds(200));
                    std::cout << "#   "<< mass[j][1] << std::endl;
                }
            }
        }
    }
    return;

}


#include <thread>
#include <chrono>
#include <iostream>
#include"line.h"


int main(void) {

    setlocale(LC_ALL,"Ukr");

    class line qs;

    qs.name("queue");
    int numq = qs.returnnum("queue");
    for (int i = 0; i < numq; i++) {
        
        qs.fullline("queue");
    }
    qs.print("queue");
    std::cout << std::endl;

    qs.name("stack");
    int nums = qs.returnnum("stack");
    for (int i = 0; i < nums; i++) {

        qs.fullline("stack");
    }
    qs.print("stack");
    std::cout << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
    


    auto ret =[&qs](std::string name) {
        qs.printmass(name);
    };

    std::thread second(ret,"stack");

    qs.printmass("queue");
    
    second.join();

    return 0;
}

7

Re: Потоки

Львівский сирник в мульти написав:

Могли б Ви глянути код?

Нащо?

Львівский сирник в мульти написав:

Потрібно вивести одночасно 2 рядочки тексту( черги та стеку) але я зміг вивести їх тільки вертикально... Не знаю як зробити горизонтально.

А проблема в чому?

Re: Потоки

Коли виводити на консоль горизонтально стек і чергу, я не зможу переключатися між рядками, тому все буде одночасно виводитись у 1-ому,2-ому,3-ому і ТД. Ось придумав тільки що можна вивести вертикально (і то працює криво, довелось незаповнені клітинки заповнювати '#').

9 Востаннє редагувалося koala (13.01.2021 23:01:36)

Re: Потоки

Стандартна консоль не призначена для красивих ефектів. Можете використовувати якісь специфічні для ОС бібліотеки (як windows.h) чи кросплатформові (як ncruses); можете взагалі використовувати щось графічне. Але я б вам радив зосередитися не на красі ефектів, а на коректності роботи потоків.

Re: Потоки

Найшов завдання цікаве про шлюбки, але не можу виканоти... Як можна створити потоки в циклі, щоб програма вічно працювала?

#include <string>

struct node;

class boat {

    private:

        struct node* mass;
        std::string name;
        int load;

    public:

        void addboat();
        node** returnfst();
        int returnload();
        std::string returnname();
        void addmass(class boat, struct node**);
        void newnass(struct node**);

};

struct node {

    struct node* next;
    class boat bt;
};
#pragma once
#include "boat.h"


class tunnel :public boat{

    private:

        struct node* first;

    public:
        
        void addline(struct node*,struct node**);
        node** returntun();
        void newtunnel(struct node**);
};
#pragma once
#include"tunnel.h"
#include "boat.h"
class bearth : public tunnel{

    public:
        std::string name;

        void cleanboat(node*);
        void addname(std::string);
        std::string returnst();

};
#include "bearth.h"
#include <iostream>
#include <chrono>
#include <mutex>
#include <thread>
#include "boat.h"


void bearth::cleanboat(node* tunnel) {

    node* full = tunnel;
    
        if (returnst() == full->bt.returnname()) {
            if (full->bt.returnload() == 10) {
                std::this_thread::sleep_for(std::chrono::milliseconds(250));
                std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 1 хвилину." <<std::endl;
            }
            else {
                if (full->bt.returnload() == 50) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(1250));
                    std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 5 хвилину." << std::endl;
                }
                else {
                    if (full->bt.returnload() == 100) {
                        std::this_thread::sleep_for(std::chrono::milliseconds(2500));
                        std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 10 хвилин." << std::endl;
                    }


                }
            }
        }
        else {
            if (returnst() == full->bt.returnname()) {
                if (full->bt.returnload() == 10) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(250));
                    std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 1 хвилину."<< std::endl;
                }
                else {
                    if (full->bt.returnload() == 50) {
                        std::this_thread::sleep_for(std::chrono::milliseconds(1250));
                        std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 5 хвилин." << std::endl;
                    }
                    else {
                        if (full->bt.returnload() == 100) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(2500));
                            std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 10 хвилин." << std::endl;
                        }


                    }
                }
            }else{
                if (returnst() == full->bt.returnname()) {
                    if (full->bt.returnload() == 10) {
                        std::this_thread::sleep_for(std::chrono::milliseconds(250));
                        std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() <<" за 1 хвилину."<< std::endl;
                    }
                    else {
                        if (full->bt.returnload() == 50) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(1250));
                            std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 5 хвилин." << std::endl;
                        }
                        else {
                            if (full->bt.returnload() == 100) {
                                std::this_thread::sleep_for(std::chrono::milliseconds(2500));
                                std::cout << "Корабель із " << full->bt.returnname() << "-ом розгружено на причалі " << returnst() << " за 10 хвилин." << std::endl;
                            }


                        }
                    }
                }

            }
        }
    
}

void bearth::addname(std::string na) {

    name = na;

}

std::string bearth::returnst() {

    return name;

}
#include "tunnel.h"
#include "boat.h"

void tunnel::addline(struct node* boat,struct node**fst) {

    if ((*fst) == nullptr) {
        (*fst) = new node;
        (*fst)->bt = boat->bt;
        (*fst)->next = nullptr;
    }
    else {
        struct node* last = (*fst);
        while (last->next != nullptr) {
            last = last->next;
        }
        last->next = new node;
        last = last->next;
        last->bt = boat->bt;
        last->next = nullptr;
    }

}

node** tunnel::returntun() {

    return &first;

}


void tunnel::newtunnel(struct node** nt) {

    first = (*nt)->next;
}
#include "boat.h"
#include <iostream>

void boat::addboat(){
    
    int nm = rand()%3;
    int waight = rand() % 3;
    if (nm == 0) {
        if (waight == 0) {
            name = "Хліб";
            load = 10;
        }
        else {
            if (waight == 1) {
                name = "Хліб";
                load = 50;
            }
            else {
                if (waight == 2) {
                    name = "Хліб";
                    load = 100;
                }
            }
        }
    }
    else {
        if (nm == 1) {
            if (waight == 0) {
                name = "Банан";
                load = 10;
            }
            else {
                if (waight == 1) {
                    name = "Банан";
                    load = 50;
                }
                else {
                    if (waight == 2) {
                        name = "Банан";
                        load = 100;
                    }
                }
            }
        }
        else {
            if (nm == 2) {
                if (waight == 0) {
                    name = "Одяг";
                    load = 10;
                }
                else {
                    if (waight == 1) {
                        name = "Одяг";
                        load = 50;
                    }
                    else {
                        if (waight == 2) {
                            name = "Одяг";
                            load = 100;
                        }
                    }
                }
            }

        }

    }
    
}

int boat::returnload() {

    return load;

}

std::string boat::returnname() {

    return name;

}

void boat::addmass(class boat boat, struct node** fst) {

    if ((*fst) == nullptr) {
        (*fst) = new node;
        (*fst)->bt = boat;
        (*fst)->next = nullptr;
    }
    else {
        struct node* last = (*fst);
        while (last->next != nullptr) {
            last = last->next;
        }
        last->next = new node;
        last = last->next;
        last->bt = boat;
        last->next = nullptr;
    }

}

node** boat::returnfst() {

    return &mass;

}

void boat::newnass(struct node** nnode) {

    mass = (*nnode)->next;
}
#include <iostream>
#include <chrono>
#include <mutex>
#include <thread>
#include "boat.h"
#include "tunnel.h"
#include "bearth.h"

std::mutex mx1;
std::mutex mx2;
std::mutex mx3;


int main(void) {

    setlocale(LC_ALL, "");
    boat mass;
    tunnel line;
    
    

    bearth bana;
    bearth clothe;
    bearth  bre;
    bana.addname("Банан");
    clothe.addname("Одяг");
    bre.addname("Хліб");
    node* ma;
    auto fu1 = [&mass]() {
        
            mx1.lock();
            
            boat newb;
            newb.addboat();
            newb.addmass(newb, (mass.returnfst()));
            std::cout << "Шлюбку додано." << std::endl;
            mx1.unlock();
        
    };
    

    auto fu2 = [&line,&mass]() {
        
            mx1.lock();
            mx2.lock();
            
            line.addline(*mass.returnfst(), line.returntun());
            mass.newnass(mass.returnfst());
            std::cout << "Шлюбку додано в тунель." << std::endl;
            mx2.unlock();
            mx1.unlock();
        
    };

    auto fu3 = [&bre,&bana,&clothe,&line]() {
        
            mx2.lock();
            mx3.lock();
            
            bre.cleanboat(*line.returntun());
            bana.cleanboat(*line.returntun());
            clothe.cleanboat(*line.returntun());
            

            line.newtunnel(line.returntun());

            mx3.unlock();
            mx2.unlock();
        
    };
    
    
        std::thread td1(fu1);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        std::thread td2(fu2);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        std::thread td3(fu3);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        std::thread td4(fu1);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        std::thread td5(fu2);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        std::thread td6(fu3);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    
        std::thread td7(fu1);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        std::thread td8(fu2);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        std::thread td9(fu3);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    
        td9.join();
        td8.join();
        td7.join();

        td6.join();
        td5.join();
        td4.join();

        td3.join();
        td2.join();
        td1.join();
    
    return 0;

}

Ось завдання :
Задание было следующее:

Есть транспортные корабли, которые подплывают к туннели и далее плывут к причалам для погрузки разного рода товара.
Они проходят через узкий туннель где одновременно могут находиться только 5 кораблей. Под словом “подплывают к туннели” имеется ввиду то, что корабли должны откуда-то появляться. Их может быть ограниченное количество, то есть 10 или 100, а может быть бесконечное множество. Слово “Подплывают” назовем генератором кораблей.
Вид кораблей и их вместительность могут быть разными в зависимости от типа товаров, которые нужно загрузить на корабль. То есть для ТЗ я придумал 3 Типа кораблей (Хлеб, Банан и Одежда) и три вида вместительности 10, 50, 100 шт. товаров. 3 типа кораблей * 3 вида вместительности = 9 разных видов кораблей.
Далее есть 3 вида причалов для погрузки кораблей — Хлеб, Банан и Одежда. Каждый причал берет или подзывает к себе необходимый ему корабль и начинает его загружать. За одну секунду причал загружает на корабль 10 ед. товара. То есть если у корабля вместительность 50 шт., то причал загрузит его за 5 секунд своей работы.

Требование было следующее:

Правильно разбить задачу на параллельность.
Синхронизировать потоки, сохранить целостность данных. Ведь ограничить доступ потоков к общему ресурсу дело не сложное, а заставить их работать согласованно уже намного сложнее.
Работа генератора кораблей не должна зависеть от работы причалов и наоборот.
Общий ресурс должен быть Thread Safe (Если таковой есть в реализации)
Потоки не должны быть активными если нет задач.
Потоки не должны держать mutex если нет задач.

11

Re: Потоки

Ви п.1.1 Правил бачили? При реєстрації галочку ставили?

12

Re: Потоки

українською! не розумію вашої мови.

while(1) {
/* . . . */
}

Re: Потоки

lucas-kane написав:

українською! не розумію вашої мови.

while(1) {
/* . . . */
}

Я так пробував, але вибиває помилку. І програма зупиняється .

Подякували: hyhot1

14 Востаннє редагувалося Львівский сирник в мульти (16.01.2021 20:14:57)

Re: Потоки

Вимога було наступне:

Правильно розбити задачу на паралельність.
Синхронізувати потоки, зберегти цілісність даних. Адже обмежити доступ до загального ресурсу справа не складна, а змусити їх працювати злагоджено вже набагато складніше.
Робота генератора кораблів не повинна залежати від роботи причалів та навпаки.
Загальний ресурс повинен бути Thread Safe (Якщо такий є в реалізації)
Потоки не повинні бути активними якщо немає завдань.
Потоки не повинні тримати mutex якщо немає завдань

Подякували: hyhot1

15

Re: Потоки

Тульський пряник іде в бан до понеділка.

Подякували: Лудоман1

16

Re: Потоки

Жорстоко...

Подякували: hyhot1

17

Re: Потоки

Львівский сирник в мульти написав:
lucas-kane написав:

українською! не розумію вашої мови.

while(1) {
/* . . . */
}

Я так пробував, але вибиває помилку. І програма зупиняється .

Взагалі, то був жарт. Але якщо Ви вже так пробували... ))) (не маю що сказати)

Подякували: Лудоман1

18

Re: Потоки

Лудоман іде в перманентний бан за п.2.1 Правил.
Бан Сирнику тепер ще й по IP, до 20 числа.

Подякували: leofun011

19

Re: Потоки

koala написав:

Ви п.1.1 Правил бачили?

а ви бачили? там нічого не написано про бан за іншу мову. Невже так складно написати нормальні правила, які не допускають свавілля модераторів.

Re: Потоки

Thread Safe що це? Не можу знайти