Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Многопоточность С++

Многопоточность — это особая форма многозадачности, а многозадачность — это функция, которая позволяет вашему компьютеру одновременно запускать две или более программы. Как правило, существует два типа многозадачности:на основе процессов и на основе потоков.

Многозадачность на основе процессов обеспечивает одновременное выполнение программ. Многозадачность на основе потоков связана с одновременным выполнением частей одной и той же программы.

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

C++ не содержит встроенной поддержки многопоточных приложений. Вместо этого он полностью полагается на операционную систему для предоставления этой функции.

В этом руководстве предполагается, что вы работаете в ОС Linux, и мы собираемся написать многопоточную программу на C++ с использованием POSIX. POSIX Threads или Pthreads предоставляет API, который доступен во многих Unix-подобных системах POSIX, таких как FreeBSD, NetBSD, GNU/Linux, Mac OS X и Solaris.

Создание тем

Следующая процедура используется для создания потока POSIX —

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

Здесь pthread_create создает новый поток и делает его исполняемым. Эту подпрограмму можно вызывать любое количество раз из любого места вашего кода. Вот описание параметров —

<тд>

поток

Непрозрачный уникальный идентификатор нового потока, возвращаемый подпрограммой.

<тд>

атрибут

Непрозрачный объект атрибута, который можно использовать для установки атрибутов потока. Вы можете указать объект атрибутов потока или NULL для значений по умолчанию.

<тд>

начать_процедуру

Подпрограмма C++, которую будет выполнять поток после его создания.

<тд>

аргумент

Единственный аргумент, который может быть передан в start_routine. Он должен передаваться по ссылке в виде указателя типа void. NULL может использоваться, если аргумент не передается.

Старший № Параметр и описание
1
2
3
4

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

Завершение потоков

Существует следующая процедура, которую мы используем для завершения потока POSIX —

#include <pthread.h>
pthread_exit (status) 

Здесь pthread_exit используется для явного выхода из потока. Как правило, подпрограмма pthread_exit() вызывается после того, как поток завершил свою работу, и его существование больше не требуется.

Если функция main() завершается раньше созданных ею потоков и завершается с помощью pthread_exit(), другие потоки продолжают выполняться. В противном случае они будут автоматически завершены после завершения main().

Пример

Этот простой пример кода создает 5 потоков с помощью процедуры pthread_create(). Каждый поток печатает «Hello World!» сообщения, а затем завершается вызовом pthread_exit().

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   
   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Скомпилируйте следующую программу, используя библиотеку -lpthread следующим образом —

$gcc test.cpp -lpthread

Теперь запустите вашу программу, которая выдаст следующий результат —

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4

Передача аргументов в потоки

В этом примере показано, как передать несколько аргументов через структуру. Вы можете передать любой тип данных в обратном вызове потока, потому что он указывает на void, как объяснено в следующем примере —

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

struct thread_data {
   int  thread_id;
   char *message;
};

void *PrintHello(void *threadarg) {
   struct thread_data *my_data;
   my_data = (struct thread_data *) threadarg;

   cout << "Thread ID : " << my_data->thread_id ;
   cout << " Message : " << my_data->message << endl;

   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   struct thread_data td[NUM_THREADS];
   int rc;
   int i;

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout <<"main() : creating thread, " << i << endl;
      td[i].thread_id = i;
      td[i].message = "This is message";
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message

Присоединение и отсоединение потоков

Есть следующие две процедуры, которые мы можем использовать для присоединения или отсоединения потоков —

pthread_join (threadid, status) 
pthread_detach (threadid) 

Подпрограмма pthread_join() блокирует вызывающий поток до тех пор, пока указанный поток 'threadid' не завершится. Когда создается поток, один из его атрибутов определяет, является ли он присоединяемым или отсоединяемым. Только потоки, которые созданы как присоединяемые, могут быть объединены. Если цепочка создается как отсоединенная, к ней невозможно присоединиться.

В этом примере показано, как дождаться завершения потока с помощью процедуры соединения Pthread.

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define NUM_THREADS 5

void *wait(void *t) {
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}

int main () {
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;

   // Initialize and set thread joinable
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], &attr, wait, (void *)i );
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // free attribute and wait for the other threads
   pthread_attr_destroy(&attr);
   for( i = 0; i < NUM_THREADS; i++ ) {
      rc = pthread_join(threads[i], &status);
      if (rc) {
         cout << "Error:unable to join," << rc << endl;
         exit(-1);
      }
      cout << "Main: completed thread id :" << i ;
      cout << "  exiting with status :" << status << endl;
   }

   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0  exiting with status :0
Main: completed thread id :1  exiting with status :0
Main: completed thread id :2  exiting with status :0
Main: completed thread id :3  exiting with status :0
Main: completed thread id :4  exiting with status :0
Main: program exiting.

Язык C

  1. Операторы С++
  2. С++ Комментарии
  3. Шаблоны классов С++
  4. Обзор С++
  5. Константы/литералы С++
  6. Операторы в С++
  7. Числа в С++
  8. Ссылки на С++
  9. Шаблоны С++
  10. Многопоточность С++