Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/58: Рейтинг темы: голосов - 58, средняя оценка - 4.71
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524

Потоко-безопасная Очередь

05.04.2021, 20:16. Показов 12784. Ответов 106
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
... вырисовалась тема отсюда
Цитата Сообщение от zayats80888 Посмотреть сообщение
Хотя не сложно написать такую очередь(с раздельной блокировкой для "хвоста" и "головы") самостоятельно.
вот выполнила последнюю задачку отсюда - но не знаю, может лучше shared_mutex вместо просто mutex? правда на него unique_lock<shared_mutex> не ставится...
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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 
using namespace std;
 
  bool bDone;
  mutex m;
  std::condition_variable cv;
 
int main() {
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    thread producer([&]() {
        std::lock_guard<mutex> lock(m);
        for (int i = 0; i < 500; ++i) {            
            goods.push(i);
            c++;
            cv.notify_one();
        }
 
        done = true;
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        while (!done) {
            while (!goods.empty()) {
                goods.pop();
                c--;
                while (!bDone) cv.wait(lock);
            }
        }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}
тут же не раздельная блокировка? - это FIFO, насколько понимаю...
а раздельная - вы, наверно, имеете ввиду для LIFO... наверно лучше на list выполнять?
sorry, что много вопросов - стою на распутье - даже в отдельную тему вынесла
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.04.2021, 20:16
Ответы с готовыми решениями:

Потоко-независимая очередь записывает 2е команды в одну ячейку. Почему ?
Доброго времени суток. Написал 2а приложения общяющихся между собой по TCP. Одно является сервером(планшет), второе клиент(windows). ...

Потоко-безопасный ObservableCollection с AddRange
Вообщем, я заполняю в нескольких потоках массив. на данный момент использую &quot;List&lt;ExpandoObject&gt; Вывод&quot; из-за...

Является ли boost::asio::tcp::acceptor потоко-безопасным ?
Мне сложно понять смысл того что написано в документации: ...

106
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.04.2021, 20:20
Цитата Сообщение от JeyCi Посмотреть сообщение
вот выполнила последнюю задачку отсюда - но не знаю, может лучше shared_mutex? правда на него unique_lock<shared_mutex> не ставится...
У тебя оба потока изменяют очередь. Смысла использовать shared_mutex здесь нет.

Добавлено через 38 секунд
Цитата Сообщение от JeyCi Посмотреть сообщение
правда на него unique_lock<shared_mutex> не ставится...
Вроде прекрасно ставится

Добавлено через 1 минуту
Только надо использовать std::condition_variable_any. Не рекомендую.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 20:22
Цитата Сообщение от JeyCi Посмотреть сообщение
тут же не раздельная блокировка?
Нет, тут один mutex.
Цитата Сообщение от JeyCi Посмотреть сообщение
а раздельная - вы, наверно, имеете ввиду для LIFO... наверно лучше на list выполнять?
Нет, FIFO, и да, list, только самописный(со стандартным не получится, т.к. для этого нужен "мнимый" узел).

Ну и ваш producer не отпускает блокировку на протяжении всего времени работы.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 20:22
del
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
05.04.2021, 20:27  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Вроде прекрасно ставится
т.е. ставится, но с CV не работает -
c #include <shared_mutex> в том коде и всеми shared_mutex дальше по коду:
error: no matching function for call to 'std::condition_variable::wait(std::uniq ue_lock<std::shared_mutex>&)'
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.04.2021, 20:27
Цитата Сообщение от JeyCi Посмотреть сообщение
error: no matching function for call to 'std::condition_variable::wait(std::uniq ue_lock<std::shared_ mutex>&)'
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Только надо использовать std::condition_variable_any. Не рекомендую.
+++
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
05.04.2021, 21:01  [ТС]
и классом - такая мне нравится
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
// A threadsafe-queue.
// https://stackoverflow.com/questions/15278343/c11-thread-safe-queue
 
#include <queue>
#include <mutex>
#include <condition_variable>
 
template <class T>
class SafeQueue
{
public:
  SafeQueue(void)
    : q()
    , m()
    , c()
  {}
 
  ~SafeQueue(void)
  {}
 
  // Add an element to the queue.
  void enqueue(T t)
  {
    std::lock_guard<std::mutex> lock(m);
    q.push(t);
    c.notify_one();
  }
 
  // Get the "front"-element.
  // If the queue is empty, wait till a element is avaiable.
  T dequeue(void)
  {
    std::unique_lock<std::mutex> lock(m);
    while(q.empty())
    {
      // release lock as long as the wait and reaquire it afterwards.
      c.wait(lock);
    }
    T val = q.front();
    q.pop();
    return val;
  }
 
private:
  std::queue<T> q;
  mutable std::mutex m;
  std::condition_variable c;
};
простенький use
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
 
#include "safe_queue.h"
 
using namespace std;
 
int main(int argc, const char *argv[])
{
    SafeQueue<int> sq;
    sq.enqueue(5);
    sq.enqueue(2);
    sq.enqueue(3);
    
    cout <<sq.dequeue()<<endl;
    cout <<sq.dequeue()<<endl;
    cout <<sq.dequeue()<<endl;
    
    return 0;
}
как зациклить вывод не знаю ... наверно, всё-таки итератор надо делать в классе?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.04.2021, 21:05
Цитата Сообщение от JeyCi Посмотреть сообщение
как зациклить вывод не знаю ... наверно, всё-таки итератор надо делать в классе
Лучше предусмотри вот такой случай
C++
1
2
3
4
5
6
7
8
int main(int argc, const char *argv[])
{
    SafeQueue<int> sq;
    
    cout <<sq.dequeue()<<endl;
stc::cout << "Finish!!!" << std::endl;
    return 0;
}
На практике смысла в таких классах немного.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
05.04.2021, 21:34  [ТС]
перегрузить << ?
кстати variadic-template можно подрядить в сам класс, наверно ? (тоже для вывода - рекурсивно)... правда с разделителем (хотя бы '\n') там засада...

Добавлено через 19 минут
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
На практике смысла в таких классах немного.
что ещё посоветуете добавить в этот класс, чтобы был смысл в его использовании?
я, конечно, понимаю, что класс есть смысл создавать, когда в него надо инкапсулировать какой-либо ресурс, чтобы корректно создавался объект и корректно удалялся (т.е. в стиле RAII)... иначе да, согласна - смысла нет, разве что - чтобы не дублировать этот код дальше

Добавлено через 4 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
ваш producer не отпускает блокировку на протяжении всего времени работы.
значит так ? на каждый loop
C++
1
2
3
4
5
6
7
8
9
10
    thread producer([&]() {        
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);           
            goods.push(i);
            c++;
            cv.notify_one();
        }
 
        done = true;
    });
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.04.2021, 21:35
Цитата Сообщение от JeyCi Посмотреть сообщение
что ещё посоветуете добавить в этот класс, чтобы был смысл в его использовании?
Ничего.
condition_variable и мьютекс нужны для потоков, которые работают с этой очередью и не только с ней. Запихивать их внутрь класса "очередь" бессмысленно.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 22:36
Цитата Сообщение от JeyCi Посмотреть сообщение
значит так ? на каждый loop
Да, только освобождать блокировку можно чуть раньше, перед уведомлением.
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
и не только с ней
Как раз это уже бессмысленно. condition_variable и мьютекс - деталь реализации очереди, потокам знать о них не нужно, есть интерфейс.
Завтра я захочу реализовать lock-free очередь с тем же интерфейсом - и мне не придётся переделывать код где она используется.
Смысл тот же, что и у всех классов - инкапсуляция, повторное использование кода и т.д.

---

Цитата Сообщение от JeyCi Посмотреть сообщение
что ещё посоветуете добавить в этот класс, чтобы был смысл в его использовании?
Настоятельно рекомендую вдумчиво прочитать книгу Уильямса("Параллельное программирование на С++ в действии").
Там всё постепенно и доступно объясняется(в том числе есть примеры очередей, как с мьютексами, так и lock-free).
Просто вы выдёргиваете информацию из разных мест, в итоге в голове будет каша, а тема на самом деле не простая.
Если нет времени на книги, то пользуйтесь готовыми решениями(библиотечными, а не портянками с сайтов и форумов).
1
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
05.04.2021, 22:46
Цитата Сообщение от zayats80888 Посмотреть сообщение
Как раз это уже бессмысленно. condition_variable и мьютекс - деталь реализации очереди, потокам знать о них не нужно, есть интерфейс.
Завтра я захочу реализовать lock-free очередь с тем же интерфейсом - и мне не придётся переделывать код где она используется.
Смысл тот же, что и у всех классов - инкапсуляция, повторное использование кода и т.д.
Инкапсуляция потокобезопаности внутрь абстрагированных от бизнес-логики контейнеров - это довольно часто вредно на практике, т.к. потокобезопаность почти всегда реализуется исходя из требований бизнес-логики. По этой причине вне академических примеров или каких-то специальных случаев, на которые хорошо ложатся именно инкапсулированные решения (например, некоторые типы математических расчетов), нет смысла ничего инкапсулировать. По крайней мере делать это заранее, без анализа требований, точно не стоит.

Что касается легкой замены на lock-free, то это в некотором роде самообман: обычно решения, хорошо работающие с блокировками плохо работают с lock-free и наоборот. Тут не все так однозначно, чтобы настолько сильно уповать на простую замену одного на другое.
2
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 23:06
Цитата Сообщение от DrOffset Посмотреть сообщение
это довольно часто вредно на практике, т.к. потокобезопаность почти всегда реализуется исходя из требований бизнес-логики
Если не трудно, можете чуть подробнее(простенький пример на словах)? Т.е. в интерфейсе не вседа можно предусмотреть поведение, требуемое бизнес-логикой?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
05.04.2021, 23:14
zayats80888, вот пример того, о чем я выше говорил:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(queue.empty()) // 1 internal lock or lock-free access 
{
    // logic 1
}
else 
{
    // здесь у нас во-первых рассинхронизировано состояние 1 и состояние 2 - в зависимости от требований 
    //  это может быть критично или нет, но это явно лишняя проблема на пустом месте
    // во-вторых мы получаем две блокировки, хотя потенциально здесь нужна всего одна.
    //  в данном случае выгоднее взять обычную непотокобезопасную очередь, а синхронизацию организовать
    //  на том уровне абстракции, на котором возможно предусмотреть ее эффективную работу
 
    auto v = queue.pop(); // 2 internal lock or lock-free access
    // logic 2
}
Добавлено через 4 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
Т.е. в интерфейсе не вседа можно предусмотреть поведение, требуемое бизнес-логикой?
Можно предусмотреть, но это уже будет специализированное решение под заданные условия. Назвать такое решение "потокобезопасная очередь" уже не получится. Это будет какая-то сущность прибитая к логике задачи. И это прекрасно, потому что так будет возможность решить задачу максимально эффективно, хоть и не прибегая к красивой абстракции "потокобезопасной очереди".
2
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
06.04.2021, 09:22  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
освобождать блокировку можно чуть раньше, перед уведомлением.
ок... и запихнуть это в INTERLOCKED_ в U++ (в котором пишу)
а то там свои примитивы синхронизации

Добавлено через 8 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
По этой причине вне академических примеров или каких-то специальных случаев, на которые хорошо ложатся именно инкапсулированные решения (например, некоторые типы математических расчетов), нет смысла ничего инкапсулировать.
спасибо! действительно, многопоточность для CPU-bound решений (ака математика, когда она долгая и можно разделить на части) - красивое решение (с барьерами), правда на с - потому что, действительно, появляется смысл
время выполнения в 4 потока, как это ни удивительно, в 4 раза быстрее
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
06.04.2021, 09:31  [ТС]
оставлю красивую шпаргалку по мьютексам для истории
Миниатюры
Потоко-безопасная Очередь  
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
06.04.2021, 10:03  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Что касается легкой замены на lock-free, то это в некотором роде самообман: обычно решения, хорошо работающие с блокировками плохо работают с lock-free и наоборот.
да, помню, я мечтала о lock-free

Добавлено через 2 минуту
p.s.
и кстати по линку, откуда задачка из #1, - и atomic показан (более быстрой заменой мьютексу) - для простых типов
и случаи ускорения, выбирая нужный мьютекс

Добавлено через 21 минуты
p.p.s.
ой забыла линк на шпаргалку оставить
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 16:57  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Да, только освобождать блокировку можно чуть раньше, перед уведомлением.
работает нестабильно - иногда зависает, ничего не выведя (ни вариант под спойлером, ни он же с закомментированной блокировкой в consumer) - возможно, прчина Deadlock??
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 
using namespace std;
 
  bool bDone;
  mutex m;
  std::condition_variable cv;
 
int main() {
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    thread producer([&]() {        
        for (int i = 0; i < 500; ++i) { 
            {
                std::lock_guard<mutex> lock(m);           
                goods.push(i);
                c++;
            }
            cv.notify_one();
        }
 
        done = true;
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        while (!done) {
            while (!goods.empty()) {
                goods.pop();
                c--;
                while (!bDone) cv.wait(lock);
            }
        }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}

а лочить на всего producer'a, действительно, не добавит performance... но, возможно это подразумевалось в задаче... вариант ping-pong немного сложнее - доп. флаги используются...

Добавлено через 2 минуты
ping-pong

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//----------------------------------------------------------------------------- 
// File: Program.h 
// https://tatourian.blog/2013/03/26/producer-consumer-inter-thread-communication-using-condition-variables-in-c/
// Desc: Demonstrates inter-thread communication using condition variables. 
//       Producer and consumer threads will ping-pong between each other. 
//       Code can be modified in such a way that producer will read and queue  
//         chunks of data from some source, network stream for example, while 
//         consumer thread will process data from the queue. In that scenario, 
//         ping-ponging will not be required as consumer should be disposing of data 
//         independently of producer queuing it. 
// 
//----------------------------------------------------------------------------- 
 
#include <chrono> 
#include <condition_variable> 
#include <iostream> 
#include <mutex> 
#include <queue> 
#include <thread> 
 
using std::cout; 
using std::endl; 
using std::condition_variable; 
using std::lock_guard; 
using std::unique_lock; 
using std::mutex; 
using std::queue; 
using std::thread; 
using std::chrono::milliseconds; 
using std::this_thread::sleep_for; 
 
static const int MagicNumber = 30;                            // Magic number used for the sample, remove it for production code 
 
int main() 
{ 
    condition_variable    m_alarm;                            // Notifies threads that more work is available 
    mutex                m_mutex;                            // Synchronizes access to shared variables 
    queue<int>            m_queue;                            // Accumulates data chunks 
    bool                m_isNotified = false;                // This is a guard to prevent accidental spurious wakeups 
    bool                m_haveData   = true;                // Only used for this sample to end consumer thread, not required in production code 
 
    thread producer([&m_mutex, &m_queue, &m_alarm, &m_isNotified, &m_haveData]() { 
        for (int i = 0; i < MagicNumber; ++i) 
        { 
            sleep_for(milliseconds(500));                    // Executing some long operation 
            lock_guard<mutex> lock(m_mutex);                // Enter critical section 
            cout << "producer " << i << endl; 
            m_queue.push(i);                                // Add data chunk to the queue 
            m_isNotified = true;                            // Consumer can be woken up and it is not a fluke (see spurious wakeups) 
            m_alarm.notify_one();                            // Notify consumer 
        } 
 
        lock_guard<mutex> lock(m_mutex);                    // Work is done, app can exit 
        m_isNotified = true; 
        m_haveData = false; 
        m_alarm.notify_one(); 
    }); 
 
    thread consumer([&m_mutex, &m_queue, &m_alarm, &m_isNotified, &m_haveData]() { 
        while (m_haveData)                                    // In production, this check will be done on whether there is more data in the queue 
        { 
            unique_lock<mutex> lock(m_mutex);                // Must aquire unique_lock with condition variables 
 
            while (!m_isNotified)                            // Prevents from spurious wakeup 
            { 
                m_alarm.wait(lock);                            // Wait for a signal from producer thread 
            } 
 
            while (!m_queue.empty())                        // Process data and remove it from the queue 
            { 
                cout << "consumer " << m_queue.front() << endl; 
                m_queue.pop(); 
            } 
 
            m_isNotified = false;                            // Protect from spurious wakeup 
        } 
    }); 
 
    // Join threads and finish app 
    producer.join(); 
    consumer.join(); 
 
    return 0; 
}
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
07.04.2021, 17:03
Лучший ответ Сообщение было отмечено JeyCi как решение

Решение

Цитата Сообщение от JeyCi Посмотреть сообщение
работает нестабильно
Правильно. Потому что нельзя освобождать блокировку перед уведомлением. Уважаемый zayats80888 здесь был неточен.
1
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 17:09
Цитата Сообщение от DrOffset Посмотреть сообщение
Правильно. Потому что нельзя освобождать блокировку перед уведомлением. Уважаемый zayats80888 здесь был неточен.
acquire a std::mutex (typically via std::lock_guard)
perform the modification while the lock is held
execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification)
https://en.cppreference.com/w/... n_variable
Если речь идёт об notify_one

Добавлено через 1 минуту
Цитата Сообщение от JeyCi Посмотреть сообщение
bool bDone;
C++
1
volatile bool bDone;
Добавлено через 42 секунды
Цитата Сообщение от JeyCi Посмотреть сообщение
while (!bDone) cv.wait(lock);
Зачем этот цикл?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.04.2021, 17:09
Помогаю со студенческими работами здесь

Сформировать односвязную очередь из элементов, которые входят в очередь Q1, но не входят в очередь Q2
Составить программу обработки динамической структуры данных: сформировать односвязную очередь Q из элементов, которые входят в очередь Q1,...

Не безопасная форма
Привет, пользуюсь менеджером паролей Lastpass, и мне интересно, что такое не безопасная форма? У разработчика спрашивал, но он объяснил что...

Безопасная работа
_http://www.webpark . ru/comments.php?id=45545

Безопасная регистрация
Всем привет. Вот я собственно попытался сделать систему регистрации, в PHP пока еще не особо силен, только понемногу начинаю учится. ...

Безопасная авторизация
Здравствуйте! Есть приложение клиент, которое обращается к wcf сервису, чтобы то произвело какие то действия. Клиент написан под...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru