Что такое поток в с
Перейти к содержимому

Что такое поток в с

Потоки и система ввода-вывода

Все инструменты для работы с системой ввода-вывода и потоками в языке С++ определены в стандартной библиотеке. Заголовочный файл iostream определяет следующие базовые типы для работы с потоками:

  • istream и wistream : читают данные с потока
  • ostream и wostream : записывают данные в поток
  • iostream и wiostream : читают и записывают данные в поток

Для каждого типа определен его двойник, который начинается на букву w и который предназначен для поддержки данных типа wchar_t.

Эти типы являются базовыми для других классов, управляющих потоками ввода-вывода.

Объект типа ostream получает значения различных типов, преобразует их в последовательность символов и передает их через буфер в определенное место для вывода (консоль, файл, сетевые интерфейсы и т.д.)

Поток вывода ostream в С++

Поток istream получает через буфер из определенного места последовательности символов (с консоли, из файла, из сети и т.д.) и преобразует эти последовательности в значения различных типов. То есть когда мы вводим данные (с той же клавиатуры в консоли), сначала данные накапливаются в буфере и только затем передаются объекту istream.

Поток ввода istream в С++

По умолчанию в стандартной библиотеке определены объекты этих классов — cout , cin , cerr , которые работают с консолью.

Запись в поток

К примеру, по умолчанию стандартная библиотека C++ предоставляет объект cout , который представляет тип ostream и позволяет выводить данные на консоль:

#include int main()

std::cout  

Чтение данных

Для чтения данных из потока применяется оператор ввода >> , который принимает два операнда. Левый операнд представляет поток istream, с которого производится считывание, а правый операнд - объект, в который считываются данные.

Для чтения с консоли применяется объект cin , который представляет тип istream.

#include int main() < int age; double weight; std::cout > age; std::cout > weight; std::cout

Однако такой способ не очень подходит для чтения строк с консоли особенно когда считываемая строка содержит пробельные символы. В этом случае лучше использовать встроенную функцию getline() , которая в качестве параметра принимает поток istream и переменную типа string, в которую надо считать данные:

#include int main() < std::string name; std::cout > name; std::cout

Пример работы программы:

Input name: Tom Smit Your name: Tom Smit

По умолчанию признаком окончания ввода служит перевод на другую строку, например, с помощью клавиши Enter. Но также можно задать свой признак окончания ввода с помощью дополнительного параметра функции getline() . Для этого надо передать символ, который будет служить окончанием ввода:

#include int main() < std::string text; std::cout << "Input text: " << std::endl; getline(std::cin, text, '*'); // окончанием ввода будет служить символ * std::cout

В данном случае ввод завершится, когда пользователь введет символ *. Таким образом, мы можем ввести многострочный текст, но при вводе звездочки ввод завершится. Пример работы программы:

Input text: Hello World Good bye world* Your text: Hello World Good bye world

Вывод ошибок

Для вывода сообщения об ошибке на консоль применяется объект cerr , который представляет объект типа ostream:

#include int main()

Потоки символов wchar_t

Для работы с потоками данных типов wchar_t в стандартной библиотеке определены объекты wcout (тип wostream), wcerr (тип wostream) и wcin (тип wistream), которые являются аналогами для объектов cout, cerr и cin и работают аналогично

#include int main() < int age; double weight; std::wcout > age; std::wcout > weight; if (age

Потоки

Системы ввода/вывода С и С++ имеют одну общую особенность: они обе оперируют потоками. То, что потоки в С и С++ подобны между собой, означает, что все, что известно о потоках в языке С, полностью применимо и в С++.

Предопределенные потоки С++

Как и в языке С, в С++ существует несколько предопределенных потоков, открывающихся автома­тически вместе с началом выполнения программы. Ими служат cin, cout, cerr и clog. Как извест­но, cin является потоком, ассоциированным со стандартным вводом, а cout представляет собой поток, ассоциированный со стандартным выводом. Потоки cerr и clog используются для вывода сообщений об ошибках. Разница между cerr и clog заключается в том, что, хотя они оба привяза­ны к стандартному выводу, cerr не буферизирован, поэтому все посланные в него данные выво­дятся немедленно. В противоположность этому clog буферизирован, так что данные выводятся только тогда, когда буфер оказывается полным.

По умолчанию стандартные потоки С++ привязаны к консоли, но программа может перена­править их на другие устройства или файлы. Они также могут быть перенаправлены операцион­ной системой.

Что такое поток (stream)?

В книжках пишут про стандартные потоки ввода-вывода в C++, запись в поток и чтение из потока. Что такое поток, и что он из себя представляет?

Отслеживать
30.9k 13 13 золотых знаков 96 96 серебряных знаков 157 157 бронзовых знаков
задан 14 июл 2015 в 15:29
357 1 1 золотой знак 2 2 серебряных знака 8 8 бронзовых знаков

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Поток это просто абстракция. Удобная абстракция для решения задач.

Но если так будет легче - считайте, что это такая труба. С одной стороны в нее пихаются данные, а с другой куда то уходят (например, на консоль или в файл). Так как труба не нулевого размера, часть данных там может "задерживаться" - это так называемая буферизация. Понимание этого может облегчить понимание некоторого странного поведения стандартных потоков.

Рассмотрим например, такое чтение с консоли:

int n; std::string s; std::cin >> n >> s; 

и такие данные на вход:

123a aaa 

Как это будет работать? Вначале стандартному потоку нужно прочитать число. Он будет читать до тех пор, пока там число. В n попадет 123. В "трубе осталось "a aaa". Дальше нужно прочитать строку. А строка читается до пробела или перевода строки. Поэтому прочитается только одно a. А многие полагают, что прочитается три а. Я привел этот пример не просто так. На него многие попадаются.

Как это реализовано внутри? Очень просто. Есть очередь (то есть, если очень грубо - массив), откуда читают данные байт за байтом. Если в очереди ничего нет - библиотечный код обращается к функциям операционной системы и читает с консоли/файла/сокета) и складывает в очередь. Конечно, в некоторых случаях эта очередь может быть реализована на базе операционной системы, а может и явно. Но для пользователя (то есть программиста) это прозрачно.

Аналогично работает и вывод.

Чем удобны потоки?

После того, как поток "подключен" к файлу или консоли, дальше все идет одинаково. Можно, к примеру написать функции, которые будут выводить в поток, но при этом абсолютно не знать, куда именно они выводят. Это позволяет писать обобщенные алгоритмы и прочие вкусности.

Например, нужно сделать функцию форматированного вывода числа на консоль (со спец. пожеланиями). Можно конечно закодить вывод на std::cout, но как протестить? Можно написать функцию, которая будет на вход получать ostream (предок std::cout) и выводить в него. Потом можно использовать такую функцию и выводить в stringstream, который легко преобразовывается в строку и результат можно выверить тестом.

Что такое поток в с

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

Для создания потока применяется один из конструкторов класса Thread :

  • Thread(ThreadStart) : в качестве параметра принимает объект делегата ThreadStart, который представляет выполняемое в потоке действие
  • Thread(ThreadStart, Int32) : в дополнение к делегату ThreadStart принимает числовое значение, которое устанавливает размер стека, выделяемого под данный поток
  • Thread(ParameterizedThreadStart) : в качестве параметра принимает объект делегата ParameterizedThreadStart, который представляет выполняемое в потоке действие
  • Thread(ParameterizedThreadStart, Int32) : вместе с делегатом ParameterizedThreadStart принимает числовое значение, которое устанавливает размер стека для данного потока

Вне зависимости от того, какой конструктор будет применяться для создания, нам надо определить выполняемое в потоке действие. В этой статье рассмотрим использование делегата ThreadStart. Этот делегат представляет действие, которое не принимает никаких параметров и не возвращает никакого значения:

public delegate void ThreadStart();

То есть под этот делегат нам надо определить метод, который имеет тип void и не принимает никаких параметров. Примеры определения потоков:

Thread myThread1 = new Thread(Print); Thread myThread2 = new Thread(new ThreadStart(Print)); Thread myThread3 = new Thread(()=>Console.WriteLine("Hello Threads")); void Print() => Console.WriteLine("Hello Threads");

Для запуска нового потока применяется метод Start класса Thread:

using System.Threading; // создаем новый поток Thread myThread1 = new Thread(Print); Thread myThread2 = new Thread(new ThreadStart(Print)); Thread myThread3 = new Thread(()=>Console.WriteLine("Hello Threads")); myThread1.Start(); // запускаем поток myThread1 myThread2.Start(); // запускаем поток myThread2 myThread3.Start(); // запускаем поток myThread3 void Print() => Console.WriteLine("Hello Threads");

Преимуществом потоком является то, что они могут выполняться одновременно. Например:

using System.Threading; // создаем новый поток Thread myThread = new Thread(Print); // запускаем поток myThread myThread.Start(); // действия, выполняемые в главном потоке for (int i = 0; i < 5; i++) < Console.WriteLine($"Главный поток: "); Thread.Sleep(300); > // действия, выполняемые во втором потокке void Print() < for (int i = 0; i < 5; i++) < Console.WriteLine($"Второй поток: "); Thread.Sleep(400); > >

Здесь новый поток будет производить действия, определенные в методе Print, то есть выводить числа от 0 до 4 на консоль. Причем после каждого вывода производится задержка на 400 миллисекунд.

В главном потоке - в методе Main создаем и запускаем новый поток, в котором выполняется метод Print:

Thread myThread = new Thread(Print); myThread.Start();

Кроме того, в главном потоке производим аналогичные действия - выводим на консоль числа от 0 до 4 с задержкой в 300 миллисекунд.

Таким образом, в нашей программе будут работать одновременно главный поток, представленный методом Main, и второй поток, в котором выполняется метод Print. Как только все потоки отработают, программа завершит свое выполнение. В итоге мы получим следующий консольный вывод:

Главный поток: 0 Второй поток: 0 Главный поток: 1 Второй поток: 1 Главный поток: 2 Второй поток: 2 Главный поток: 3 Второй поток: 3 Главный поток: 4 Второй поток: 4

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *