Чем отличается Vulkan от OpenGL?
Vulkan - это новый API для аппаратно-ускоренной графики (и общих вычислений) с использованием традиционных графических процессоров. OpenGL будет продолжать развиваться, поскольку это API более высокого уровня, чем предполагается для Vulkan. Первоначально упоминавшийся как "glNext", можно сделать вывод, что Vulkan, вероятно, в конечном итоге станет "OpenGL 5", но в конечном итоге орган по стандартизации решил, что новое название будет лучше соответствовать относительно чистому отличию API от существующих парадигм OpenGL.
Практические преимущества Vulkan для разработчиков игр заключаются в первую очередь в контроле (например, в том, что он позволяет использовать больше ИТ, потенциально позволяя улучшить оптимизацию за счет значительно большего объема предварительной работы со стороны разработчика). Конкретно:
API ориентирован на асинхронную генерацию командных буферов в нескольких потоках и последовательную обработку этих буферов в командном конвейере. Это отражает реалии современного оборудования. Большинство высококлассных и / или высокопроизводительных программ, созданных на OpenGL, сегодня реализуют подобное поведение самостоятельно; наличие поддержки API само по себе означает, что разработчикам не нужно внедрять и поддерживать этот фреймворк самостоятельно, или что они могут делать это с меньшими усилиями.
Задачи управления потоками и памятью возложены на приложение, а не на драйвер, что позволяет разработчикам игр лучше контролировать это поведение и, следовательно, потенциально более точно адаптировать это поведение к потребностям их индивидуальной игры.
Уровни проверки и диагностики могут быть включены независимо, что теоретически позволяет улучшить интеграцию инструментов с API (от чего страдает сам OpenGL) и отключить чрезмерную проверку, теоретически позволяя "графике третьего уровня" быть намного более производительной.
Нет жесткой разницы в API между мобильной и десктопной версиями, что теоретически облегчит перенос кроссплатформенных игр и, по крайней мере, уменьшит головную боль при проверке версий, которую все ненавидят.
Vulkan очень похож на C / OpenGL по внешней структуре (внешний вид вызовов API и так далее. Однако он лучше типизирован (в том смысле, что не все является голым int; есть соответствующие определения типов и так далее).
Он намного более низкого уровня, чем OpenGL. Можно ожидать скачка в операционных настройках и сложности между OpenGL и Vulkan, как это было замечено при переходе с D3D9 на D3D10, который предоставил клиенту API гораздо больше скрытых деталей работы устройства GPU. Переход на самом деле больше похож на D3D11 - 12, поскольку D3D12 сам по себе является API, очень похожим на Vulkan, с точки зрения возможностей.
💠 Источник
Если вы хотите изучать графическое программирование, советую начать с OpenGL, и после перейти на Vulkan. Vulkan требует больше знаний архитектуры компьютера и устройства графики.
Vulkan - это новый API для аппаратно-ускоренной графики (и общих вычислений) с использованием традиционных графических процессоров. OpenGL будет продолжать развиваться, поскольку это API более высокого уровня, чем предполагается для Vulkan. Первоначально упоминавшийся как "glNext", можно сделать вывод, что Vulkan, вероятно, в конечном итоге станет "OpenGL 5", но в конечном итоге орган по стандартизации решил, что новое название будет лучше соответствовать относительно чистому отличию API от существующих парадигм OpenGL.
Практические преимущества Vulkan для разработчиков игр заключаются в первую очередь в контроле (например, в том, что он позволяет использовать больше ИТ, потенциально позволяя улучшить оптимизацию за счет значительно большего объема предварительной работы со стороны разработчика). Конкретно:
API ориентирован на асинхронную генерацию командных буферов в нескольких потоках и последовательную обработку этих буферов в командном конвейере. Это отражает реалии современного оборудования. Большинство высококлассных и / или высокопроизводительных программ, созданных на OpenGL, сегодня реализуют подобное поведение самостоятельно; наличие поддержки API само по себе означает, что разработчикам не нужно внедрять и поддерживать этот фреймворк самостоятельно, или что они могут делать это с меньшими усилиями.
Задачи управления потоками и памятью возложены на приложение, а не на драйвер, что позволяет разработчикам игр лучше контролировать это поведение и, следовательно, потенциально более точно адаптировать это поведение к потребностям их индивидуальной игры.
Уровни проверки и диагностики могут быть включены независимо, что теоретически позволяет улучшить интеграцию инструментов с API (от чего страдает сам OpenGL) и отключить чрезмерную проверку, теоретически позволяя "графике третьего уровня" быть намного более производительной.
Нет жесткой разницы в API между мобильной и десктопной версиями, что теоретически облегчит перенос кроссплатформенных игр и, по крайней мере, уменьшит головную боль при проверке версий, которую все ненавидят.
Vulkan очень похож на C / OpenGL по внешней структуре (внешний вид вызовов API и так далее. Однако он лучше типизирован (в том смысле, что не все является голым int; есть соответствующие определения типов и так далее).
Он намного более низкого уровня, чем OpenGL. Можно ожидать скачка в операционных настройках и сложности между OpenGL и Vulkan, как это было замечено при переходе с D3D9 на D3D10, который предоставил клиенту API гораздо больше скрытых деталей работы устройства GPU. Переход на самом деле больше похож на D3D11 - 12, поскольку D3D12 сам по себе является API, очень похожим на Vulkan, с точки зрения возможностей.
💠 Источник
Если вы хотите изучать графическое программирование, советую начать с OpenGL, и после перейти на Vulkan. Vulkan требует больше знаний архитектуры компьютера и устройства графики.
👍3
ThinkPad — линейка ноутбуков, разработанная корпорацией IBM и выпускаемая ею с 1992 по 2005 год, с 2005 года права на производство этой серии переданы компании Lenovo.
Первые три модели ThinkPad — 700, 700C и 700T — были выпущены в октябре 1992 года. В модели 700C использовался процессор 486SLC (25 МГц), жёсткий диск объёмом 120 МБ, впервые в истории был выпущен 10,4-дюймовый цветной ЖК-дисплей.
Дизайн ноутбуков ThinkPad основан на концепции Bento Box, разработанной немецким дизайнером Ричардом Саппером. На одном из собраний с представителями IBM Саппер обратил внимание на традиционную японскую коробку для еды — Макуноути Бенто (Makunouchi Bento Box). Чёрная, квадратная, с красными отсеками внутри она оказалась идеальным прототипом ноутбука.
2 декабря 1993 года космический шаттл Endeavour доставил первый ноутбук ThinkPad в космос. Он использовался для ремонта космического телескопа «Хаббл»
если хотите, можете помочь мне собрать на Thinkpad
Первые три модели ThinkPad — 700, 700C и 700T — были выпущены в октябре 1992 года. В модели 700C использовался процессор 486SLC (25 МГц), жёсткий диск объёмом 120 МБ, впервые в истории был выпущен 10,4-дюймовый цветной ЖК-дисплей.
Дизайн ноутбуков ThinkPad основан на концепции Bento Box, разработанной немецким дизайнером Ричардом Саппером. На одном из собраний с представителями IBM Саппер обратил внимание на традиционную японскую коробку для еды — Макуноути Бенто (Makunouchi Bento Box). Чёрная, квадратная, с красными отсеками внутри она оказалась идеальным прототипом ноутбука.
2 декабря 1993 года космический шаттл Endeavour доставил первый ноутбук ThinkPad в космос. Он использовался для ремонта космического телескопа «Хаббл»
👍4🤔1 1
Работа с сокетами в C
Примерный набор библиотек, которые, скорее всего, придётся подключить выглядит так:
Сокет в Си создаётся следующим образом:
domain: Аргументом является семейство протоколов. Если Вы планируете использовать IPv4 укажите домен AF_INET.
Если нужен IPv6 то AF_INET6. Полный список смотрите в разделе MAN DESCRIPTION
type: Обычно выбирают SOCK_STREAM это надёжная упорядоченная передача байтов в режиме полный дуплекс.
Полный список типов: MAN DESCRIPTION types
protocol: Обычно выбирают 0. Если Вам нужен не 0, то Вы уже, видимо, знаете, что делаете лучше меня.
Пример:
Давайте напишем простой TCP сервер:
Примерный набор библиотек, которые, скорее всего, придётся подключить выглядит так:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
Сокет в Си создаётся следующим образом:
int socket(int domain, int type, int protocol);
domain: Аргументом является семейство протоколов. Если Вы планируете использовать IPv4 укажите домен AF_INET.
Если нужен IPv6 то AF_INET6. Полный список смотрите в разделе MAN DESCRIPTION
type: Обычно выбирают SOCK_STREAM это надёжная упорядоченная передача байтов в режиме полный дуплекс.
Полный список типов: MAN DESCRIPTION types
protocol: Обычно выбирают 0. Если Вам нужен не 0, то Вы уже, видимо, знаете, что делаете лучше меня.
Пример:
int socket(AF_INET, SOCK_STREAM, 0);
Давайте напишем простой TCP сервер:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main() {
char server_message[256] = "You have reached the server!";
// create the server socket
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// define the server address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(9002);
server_address.sin_addr.s_addr = INADDR_ANY;
// bind the socket to our specified IP and port
bind(server_socket, (struct sockaddr*) &server_address, sizeof(server_address));
// second agrument is a backlog - how many connections
// can be waiting for this socket simultaneously
listen(server_socket, 5);
int client_socket;
client_socket = accept(server_socket, NULL, NULL);
// send the message
send(client_socket, server_message, sizeof(server_message), 0);
// close the socket
close(server_socket);
return 0;
}
👍7👎2 2
ORM, или объектно-реляционное отображение — это программная технология, которая позволяет взаимодействовать с базами данных с использованием объектно-ориентированной парадигмы. Вместо того чтобы писать SQL-запросы напрямую для работы с данными в базе данных, можно использовать ORM, чтобы взаимодействовать с данными, как если бы они были объектами в вашем коде.
ORM позволяет абстрагироваться от сырых SQL запросов путем абстракций.
В этой статье мы и рассмотрим создание своей ORM на Python с документацией и публикацией на PyPI. Данный проект очень интересен со стороны реализации: ведь требуется изучить большую часть ООП, принципов и паттернов.
Мы создадим сессии, модели баз данных, различные поля, миграции и другой вспомогательный функционал. Мы разберем изнутри, как работает такая концепция и как достигается удобство работы.
Некоторые из вас могут подумать что мы изобретаем велосипед. А я в ответ скажу — сможете ли вы прямо сейчас, без подсказок, только по памяти, нарисовать велосипед без ошибок?
https://habr.com/ru/companies/timeweb/articles/851706/
ORM позволяет абстрагироваться от сырых SQL запросов путем абстракций.
В этой статье мы и рассмотрим создание своей ORM на Python с документацией и публикацией на PyPI. Данный проект очень интересен со стороны реализации: ведь требуется изучить большую часть ООП, принципов и паттернов.
Мы создадим сессии, модели баз данных, различные поля, миграции и другой вспомогательный функционал. Мы разберем изнутри, как работает такая концепция и как достигается удобство работы.
Некоторые из вас могут подумать что мы изобретаем велосипед. А я в ответ скажу — сможете ли вы прямо сейчас, без подсказок, только по памяти, нарисовать велосипед без ошибок?
https://habr.com/ru/companies/timeweb/articles/851706/
Хабр
Создаем свою ORM на python — гайд
ORM, или объектно-реляционное отображение — это программная технология, которая позволяет взаимодействовать с базами данных с использованием объектно-ориентированной парадигмы. Вместо того чтобы...
👍6🔥3 2👎1
Асинхронность, параллельность, многопроцессорность и многопоточность.
Асинхронность предполагает, что выполнение операций не блокирует поток, который их инициирует. Это означает, что программа может продолжать выполнение, не дожидаясь завершения определённой операции. Асинхронность активно используется в сетевых приложениях, веб-серверах и других системах, где важна отзывчивость. Например, в JavaScript асинхронные операции достигаются с помощью промисов и async/await. Асинхронный код позволяет избежать блокировок, но требует управления состоянием выполнения, что может привести к более сложному коду.
Например, следующий код в JavaScript демонстрирует, как асинхронная функция может выполнять запросы к API без блокировки основного потока:
Многопоточность означает возможность выполнения нескольких потоков (т.е. программных путей исполнения) в рамках одной программы. В многопоточной программе потоки могут работать параллельно (на разных ядрах) или последовательно, в зависимости от возможностей операционной системы и архитектуры процессора. Многопоточность позволяет улучшить производительность программ за счёт использования временных промежутков, когда потоки ожидают завершения операций ввода-вывода.
Например, в Java код для создания и запуска нескольких потоков может выглядеть так:
Параллельность как концепция предполагает одновременное выполнение нескольких процессов или потоков с целью повышения производительности и рационального использования ресурсов. Параллельные вычисления возможны только в многопроцессорных или многоядерных системах, где различные проверки выполняются одновременно. Ключевым моментом является то, что параллелизм — это "аппаратное" явление, в то время как многопоточность — "программное".
В языках, таких как Python, библиотека multiprocessing может быть использована для выполнения параллельных задач на разных ядрах:
Многопроцессорность (или многопроцессорные системы) представляет собой наличие нескольких процессоров в одной машине, что позволяет программам выполнять параллельные вычисления. В многопроцессорной системе можно запускать несколько экземпляров одной и той же программы в разных процессах одновременно, что полезно для работы с большими вычислительными задачами.
Теперь давайте подведем итог:
- Асинхронность — это не блокирующее выполнение операций, позволяющее оставаться отзывчивым.
- Многопоточность — это возможность выполнения нескольких потоков в рамках одной программы, управляемой одной операционной системой.
- Параллельность — это одновременное выполнение задач, требующее от оборудования поддержки многопоточности.
- Многопроцессорность — это механика, позволяющая запускать несколько процессов и пулов процессов.
Асинхронность предполагает, что выполнение операций не блокирует поток, который их инициирует. Это означает, что программа может продолжать выполнение, не дожидаясь завершения определённой операции. Асинхронность активно используется в сетевых приложениях, веб-серверах и других системах, где важна отзывчивость. Например, в JavaScript асинхронные операции достигаются с помощью промисов и async/await. Асинхронный код позволяет избежать блокировок, но требует управления состоянием выполнения, что может привести к более сложному коду.
Например, следующий код в JavaScript демонстрирует, как асинхронная функция может выполнять запросы к API без блокировки основного потока:
async function fetchData() {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
}
fetchData();
console.log('Это сообщение появится раньше, чем данные от API.');Многопоточность означает возможность выполнения нескольких потоков (т.е. программных путей исполнения) в рамках одной программы. В многопоточной программе потоки могут работать параллельно (на разных ядрах) или последовательно, в зависимости от возможностей операционной системы и архитектуры процессора. Многопоточность позволяет улучшить производительность программ за счёт использования временных промежутков, когда потоки ожидают завершения операций ввода-вывода.
Например, в Java код для создания и запуска нескольких потоков может выглядеть так:
class MyRunnable implements Runnable {
public void run() {
System.out.println("Запуск потока: " + Thread.currentThread().getName());
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}Параллельность как концепция предполагает одновременное выполнение нескольких процессов или потоков с целью повышения производительности и рационального использования ресурсов. Параллельные вычисления возможны только в многопроцессорных или многоядерных системах, где различные проверки выполняются одновременно. Ключевым моментом является то, что параллелизм — это "аппаратное" явление, в то время как многопоточность — "программное".
В языках, таких как Python, библиотека multiprocessing может быть использована для выполнения параллельных задач на разных ядрах:
import multiprocessing
def worker(num):
print(f'Работник {num}')
if __name__ == '__main__':
processes = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(i,))
processes.append(p)
p.start()
Многопроцессорность (или многопроцессорные системы) представляет собой наличие нескольких процессоров в одной машине, что позволяет программам выполнять параллельные вычисления. В многопроцессорной системе можно запускать несколько экземпляров одной и той же программы в разных процессах одновременно, что полезно для работы с большими вычислительными задачами.
Теперь давайте подведем итог:
- Асинхронность — это не блокирующее выполнение операций, позволяющее оставаться отзывчивым.
- Многопоточность — это возможность выполнения нескольких потоков в рамках одной программы, управляемой одной операционной системой.
- Параллельность — это одновременное выполнение задач, требующее от оборудования поддержки многопоточности.
- Многопроцессорность — это механика, позволяющая запускать несколько процессов и пулов процессов.
5 2 2👍1
#HEX • IT
ORM, или объектно-реляционное отображение — это программная технология, которая позволяет взаимодействовать с базами данных с использованием объектно-ориентированной парадигмы. Вместо того чтобы писать SQL-запросы напрямую для работы с данными в базе данных…
буду крайне рад если поставите плюс в рейтинг статьи) сможем +30?
Недавно вышла новая песня от научно-технического рэпа - "Язык для славян"
Я.Музыка: https://music.yandex.ru/album/33934790/track/132728259?utm_medium=copy_link
MTS MUSIC: https://music.mts.ru/album/33934790/track/132728259
1С - язык без изъян!
1С - язык для славян!
Для тех, кто решился работать в IT,
Язык 1С - вершина пути!
Я.Музыка: https://music.yandex.ru/album/33934790/track/132728259?utm_medium=copy_link
MTS MUSIC: https://music.mts.ru/album/33934790/track/132728259
1С - язык без изъян!
1С - язык для славян!
Для тех, кто решился работать в IT,
Язык 1С - вершина пути!
Грокаем глубокое обучение.pdf
19.6 MB
Грокаем глубокое обучение.Автор: Траск ЭндрюГрокаем стриминг.pdf
14.9 MB
Грокаем стриминг
Авторы: Джош Фишер, Нин ВанГрокаем алгоритмы ИИ.pdf
8.8 MB
Грокаем алгоритмы искусcтвенного интеллекта
Автор: Ришал ХарбансГрокаем_глубокое_обучение_с_подкреплением.zip
10.1 MB
Грокаем глубокое обучение с подкреплением
Автор: Моралес Мигель👍2 2 2
Компилятор Go генерирует абстрактный, портируемый ассемблер, который не привязан к конкретному оборудованию. Следовательно, сборщик Go использует этот псевдоассемблер для создания инструкций, специфичных для целевого оборудования.
Go позволяет использовать ассемблерные вставки в коде. Написание функций на ассемблере прямо в Go не так уж сложно, как кажется. В качестве примера, рассмотрим функцию sum, которая складывает два int64:
Хотя это стандартная функция, в ней отсутствует тело. Поэтому компилятор выдаст ошибку при попытке сборки программы.
Для реализации функции на ассемблере добавим файл с расширением .s:
Теперь мы можем собрать, протестировать и использовать функцию sum как обычную. Этот подход широко применяется в различных пакетах, таких как runtime, math, bytealg, syscall, reflect, crypto, позволяя использовать аппаратные оптимизации процессора и команды, отсутствующие в самом языке. Во многом благодаря этому можно создать полноценное ядро операционной системы.
Однако следует учитывать, что функции на ассемблере не могут быть оптимизированы и встроены компилятором. Для обхода этого ограничения разработчики создали встраиваемые функции.
Встраиваемые функции изначально написаны на Go, но компилятор имеет возможность использовать альтернативный вариант. Эти функции имеют особые сигнатуры, повторяющие сигнатуры процессорных команд, что позволяет компилятору заменить вызовы функций на ассемблерные инструкции, если целевая архитектура такова.
Встраиваемые функции представляют собой элегантное решение, предоставляющее доступ к низкоуровневым операциям без необходимости расширения спецификации языка. В случае отсутствия специфических примитивов sync/atomic (например, в некоторых вариантах arm), или операций из math/bits, компилятор будет вставлять полифил на обычном Go.
Источник: [встраиваемые функции в Go](https://dave.cheney.net/2019/08/20/go-compiler-intrinsics)
Go позволяет использовать ассемблерные вставки в коде. Написание функций на ассемблере прямо в Go не так уж сложно, как кажется. В качестве примера, рассмотрим функцию sum, которая складывает два int64:
func sum(a int64, b int64) int64
Хотя это стандартная функция, в ней отсутствует тело. Поэтому компилятор выдаст ошибку при попытке сборки программы.
Для реализации функции на ассемблере добавим файл с расширением .s:
text sum(sb),$0-24
movq a+0(fp), ax
addq b+8(fp), ax
movq ax, ret+16(fp)
ret
Теперь мы можем собрать, протестировать и использовать функцию sum как обычную. Этот подход широко применяется в различных пакетах, таких как runtime, math, bytealg, syscall, reflect, crypto, позволяя использовать аппаратные оптимизации процессора и команды, отсутствующие в самом языке. Во многом благодаря этому можно создать полноценное ядро операционной системы.
Однако следует учитывать, что функции на ассемблере не могут быть оптимизированы и встроены компилятором. Для обхода этого ограничения разработчики создали встраиваемые функции.
Встраиваемые функции изначально написаны на Go, но компилятор имеет возможность использовать альтернативный вариант. Эти функции имеют особые сигнатуры, повторяющие сигнатуры процессорных команд, что позволяет компилятору заменить вызовы функций на ассемблерные инструкции, если целевая архитектура такова.
Встраиваемые функции представляют собой элегантное решение, предоставляющее доступ к низкоуровневым операциям без необходимости расширения спецификации языка. В случае отсутствия специфических примитивов sync/atomic (например, в некоторых вариантах arm), или операций из math/bits, компилятор будет вставлять полифил на обычном Go.
Источник: [встраиваемые функции в Go](https://dave.cheney.net/2019/08/20/go-compiler-intrinsics)
👍3🔥1
https://github.com/alexeev-prog/carbon-colorscheme
Моя цветовая схема - Carbon.
Пока есть конфиг для терминала alacritty и sublime text.
Моя цветовая схема - Carbon.
Пока есть конфиг для терминала alacritty и sublime text.
👍5 3
Многопоточность в программировании является важным механизмом в наше время.
В семействах ОС Windows - каждая программа запускает один процесс выполнения, в котором находится как минимум один поток (нить). В процессе может находиться множество потоков, между которыми делится процессорное время. Один процесс не может напрямую обратиться к памяти другого процесса, а потоки же разделяют одно адресное пространство одного процесса. То есть в Windows - процесс это совокупность потоков.
В Linux же немного по-другому. Сущность процесса такая же, как и в Windows - это исполняемая программа со своими данными. Но вот поток в Linux является отдельным процессом (можно встретить название как "легковесный процесс", LWP). Различие такое же - процесс отдельная программа со своей памятью, не может напрямую обратиться к памяти другого процесса, а вот поток, хоть и отдельный процесс, имеет доступ к памяти процесса-родителя.
LWP процессы создаются с помощью системного вызова clone() с указанием определенных флагов.
Но также имеется такая вещь, которая называется "POSIX Threads" - библиотечка стандарта POSIX, которая организует потоки (они же нити) внутри процесса. Т.е тут уже распараллеливание происходит в рамках одного процесса.
И тут встает вопрос различия терминов "поток", "процесс", "нить" и т.д. Проблема в том, что в англоязычной литературе данные термины определяются однозначно, у нас же с нашим великим и могучим имеются противоречия, что может привести к дикому диссонансу.
Но это все в общих чертах, для более точной информации следует обратиться к соответствующей литературе, либо к официальной документации, можно почитать man'ы.
Рассмотрим создания потока/нити с помощью функций из pthread.h (POSIX Threads):
Как видно из кода, сущность потока воплощена в функции, в данном случае, threadFunc. Имя такой функции может быть произвольным, а вот возвращаемый тип и тип входного аргумента должны быть строго void*. Данная функция будет выполняться в отдельном потоке исполнения, поэтому необходимо с особой осторожностью подходить к реализации данной функции из-за доступа к одной и той же памяти родительского процесса многими потоками. Завершение достигается несколькими вариантами: поток достиг точки завершения (return, pthread_exit(0)), либо поток был завершен извне.
Создание потока происходит с помощью функции pthread_create(pthread_t *tid, const pthread_attr_t *attr, void*(*function)(void*), void* arg), где: tid - идентификатор потока, attr - параметры потока (NULL - атрибуты по умолчанию, подробности в man), function - указатель на потоковую функцию, в нашем случае threadFunc и arg - указатель на передаваемые данные в поток.
Функция pthread_join ожидает завершения потока thread. Второй параметр этой функции - результат, возвращаемый потоком.
#Linux@hex_warehouse #SysDev@hex_warehouse #Threads@hex_warehouse #CLanguage@hex_warehouse
В семействах ОС Windows - каждая программа запускает один процесс выполнения, в котором находится как минимум один поток (нить). В процессе может находиться множество потоков, между которыми делится процессорное время. Один процесс не может напрямую обратиться к памяти другого процесса, а потоки же разделяют одно адресное пространство одного процесса. То есть в Windows - процесс это совокупность потоков.
В Linux же немного по-другому. Сущность процесса такая же, как и в Windows - это исполняемая программа со своими данными. Но вот поток в Linux является отдельным процессом (можно встретить название как "легковесный процесс", LWP). Различие такое же - процесс отдельная программа со своей памятью, не может напрямую обратиться к памяти другого процесса, а вот поток, хоть и отдельный процесс, имеет доступ к памяти процесса-родителя.
LWP процессы создаются с помощью системного вызова clone() с указанием определенных флагов.
Но также имеется такая вещь, которая называется "POSIX Threads" - библиотечка стандарта POSIX, которая организует потоки (они же нити) внутри процесса. Т.е тут уже распараллеливание происходит в рамках одного процесса.
И тут встает вопрос различия терминов "поток", "процесс", "нить" и т.д. Проблема в том, что в англоязычной литературе данные термины определяются однозначно, у нас же с нашим великим и могучим имеются противоречия, что может привести к дикому диссонансу.
Но это все в общих чертах, для более точной информации следует обратиться к соответствующей литературе, либо к официальной документации, можно почитать man'ы.
Рассмотрим создания потока/нити с помощью функций из pthread.h (POSIX Threads):
#include <pthread.h>
//потоковая функция
void* threadFunc(void* thread_data){
//завершаем поток
pthread_exit(0);
}
int main(){
//какие то данные для потока (для примера)
void* thread_data = NULL;
//создаем идентификатор потока
pthread_t thread;
//создаем поток по идентификатору thread и функции потока threadFunc
//и передаем потоку указатель на данные thread_data
pthread_create(&thread, NULL, threadFunc, thread_data);
//ждем завершения потока
pthread_join(thread, NULL);
return 0;
}
Как видно из кода, сущность потока воплощена в функции, в данном случае, threadFunc. Имя такой функции может быть произвольным, а вот возвращаемый тип и тип входного аргумента должны быть строго void*. Данная функция будет выполняться в отдельном потоке исполнения, поэтому необходимо с особой осторожностью подходить к реализации данной функции из-за доступа к одной и той же памяти родительского процесса многими потоками. Завершение достигается несколькими вариантами: поток достиг точки завершения (return, pthread_exit(0)), либо поток был завершен извне.
Создание потока происходит с помощью функции pthread_create(pthread_t *tid, const pthread_attr_t *attr, void*(*function)(void*), void* arg), где: tid - идентификатор потока, attr - параметры потока (NULL - атрибуты по умолчанию, подробности в man), function - указатель на потоковую функцию, в нашем случае threadFunc и arg - указатель на передаваемые данные в поток.
Функция pthread_join ожидает завершения потока thread. Второй параметр этой функции - результат, возвращаемый потоком.
#Linux@hex_warehouse #SysDev@hex_warehouse #Threads@hex_warehouse #CLanguage@hex_warehouse
Кратко об обучении программированию
Воможно все. есть разный стартовый "капитал", с одним трудно стать "миллионером", с другим легко. но по сути при сильном желании можно все. Начинай с малого, сделай для себя программу обучения. Попробуй медленно, но верно идти к цели.
Изучите предлагаемый пример кода глазами. Читайте его несколько раз, пока вам не станет всё понятно. Каждая строчка должна быть достаточно очевидной.
Попробуй переписать в тетрадь код. Потом перепиши его в редактор, запусти, проверь на ошибки. Ищи ошибки сам, желательно по докам. Ответь на вопрос - откуда взялась эта ошибка и как ее больше не совершать?
Потом попробуй уйти от примера. Добавь сам что то новое, попробуй изучить новое путем практики. И также понимай сам код.
Такой метод обучения долгий, но действенный. Учась по такому, ты хоть и будешь отставать по времени, но зато ты прокачаешь не только навык программирования, но и другие (такие как проблем солвинг, анализ кода).
#Learning@hex_warehouse #Code@hex_warehouse
Воможно все. есть разный стартовый "капитал", с одним трудно стать "миллионером", с другим легко. но по сути при сильном желании можно все. Начинай с малого, сделай для себя программу обучения. Попробуй медленно, но верно идти к цели.
Изучите предлагаемый пример кода глазами. Читайте его несколько раз, пока вам не станет всё понятно. Каждая строчка должна быть достаточно очевидной.
Попробуй переписать в тетрадь код. Потом перепиши его в редактор, запусти, проверь на ошибки. Ищи ошибки сам, желательно по докам. Ответь на вопрос - откуда взялась эта ошибка и как ее больше не совершать?
Потом попробуй уйти от примера. Добавь сам что то новое, попробуй изучить новое путем практики. И также понимай сам код.
Такой метод обучения долгий, но действенный. Учась по такому, ты хоть и будешь отставать по времени, но зато ты прокачаешь не только навык программирования, но и другие (такие как проблем солвинг, анализ кода).
#Learning@hex_warehouse #Code@hex_warehouse
👍4 1