Latest web development tutorials

C ++ multithreading

Il multithreading è una forma specializzata di multi-tasking, multi-tasking permette lasciare che il computer di funzionare due o più programmi. In generale, due tipi di multitasking: basato sui processi e filo-based.

  • programma di multitasking basato sui processi viene eseguito contemporaneamente.
  • multitasking basato filo Processing è l'esecuzione simultanea dello stesso frammento di programma.

programma multithread contiene due o più parti che possono essere eseguiti contemporaneamente. Tale programma per ciascuna parte è chiamata un thread, ogni thread definisce un percorso separato di esecuzione.

C ++ non include il supporto integrato per applicazioni multi-threaded. Invece, è totalmente dipendente dal sistema operativo per fornire questa funzionalità.

Questo tutorial presuppone che si sta utilizzando il sistema operativo Linux, vogliamo usare POSIX scrivere multithreaded programma in C ++. API POSIX Thread o Pthread può essere fornito su diversi tipi di sistemi Unix POSIX disponibili, come FreeBSD, NetBSD, GNU / Linux, Mac OS X e Solaris.

Creare un filo

Il seguente programma, possiamo usarlo per creare un thread POSIX:

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

Qui, pthread_create crea un nuovo thread e renderlo eseguibile.Quanto segue è una descrizione dei parametri:

参数 描述
thread 指向线程标识符指针。
attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
start_routine 线程运行函数起始地址,一旦线程被创建就会执行。
arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

Quando un thread viene creato con successo, la funzione restituisce 0, se il valore di ritorno di 0 indica che non è riuscito a creare un thread.

Terminare il filo

Utilizzare la seguente procedura, possiamo usarlo per terminare un thread POSIX:

#include <pthread.h>
pthread_exit (status) 

Qui, pthread_exit utilizzato per uscire in modo esplicito un filo.In circostanze normali, la funzione pthread_exit () viene chiamato quando il lavoro fatto, senza dover continuare ad esistere dopo il thread.

Se il main () prima della fine del thread che ha creato, ed esce attraverso pthread_exit (), allora gli altri thread continueranno ad eseguire. In caso contrario, essi saranno nel main () alla fine termina automaticamente.

Esempi

Il codice di esempio semplice seguente utilizza pthread_create () funzione crea cinque fili, ogni uscita "Ciao w3big!":

#include <iostream>
// 必须的头文件是
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

// 线程的运行函数
void* say_hello(void* args)
{
    cout << "Hello w3big!" << endl;
}

int main()
{
    // 定义线程的 id 变量,多个变量使用数组
    pthread_t tids[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; ++i)
    {
        //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
        int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
        if (ret != 0)
        {
           cout << "pthread_create error: error_code=" << ret << endl;
        }
    }
    //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
    pthread_exit(NULL);
}

Utilizzare biblioteca -lpthread compilato il seguente programma:

$ g++ test.cpp -lpthread -o test.o

Ora, l'esecuzione del programma produrrà i seguenti risultati:

$ ./test.o
Hello w3big!
Hello w3big!
Hello w3big!
Hello w3big!
Hello w3big!

Il codice di esempio semplice seguente utilizza pthread_create () funzione crea cinque fili, e ricevere i parametri in ingresso. Ogni thread stampa un "Ciao w3big!" Messaggio, ed emette i parametri ricevuti, e quindi chiamare pthread_exit () termina il thread.

//文件名:test.cpp

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

using namespace std;

#define NUM_THREADS     5

void *PrintHello(void *threadid)
{  
   // 对传入的参数进行强制类型转换,由无类型指针变为整形数指针,然后再读取
   int tid = *((int*)threadid);
   cout << "Hello w3big! 线程 ID, " << tid << endl;
   pthread_exit(NULL);
}

int main ()
{
   pthread_t threads[NUM_THREADS];
   int indexes[NUM_THREADS];// 用数组来保存i的值
   int rc;
   int i;
   for( i=0; i < NUM_THREADS; i++ ){      
      cout << "main() : 创建线程, " << i << endl;
      indexes[i] = i; //先保存i的值
      // 传入的时候必须强制转换为void* 类型,即无类型指针        
      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void *)&(indexes[i]));
      if (rc){
         cout << "Error:无法创建线程," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Ora compilare ed eseguire il programma produrrà i seguenti risultati:

$ g++ test.cpp -lpthread -o test.o
$ ./test.o
main() : 创建线程, 0
main() : 创建线程, 1
main() : 创建线程, 2
main() : 创建线程, 3
main() : 创建线程, 4
Hello w3big! 线程 ID, 4
Hello w3big! 线程 ID, 3
Hello w3big! 线程 ID, 2
Hello w3big! 线程 ID, 1
Hello w3big! 线程 ID, 0

Passare parametri a un thread

Questo esempio mostra come passare più parametri struttura. È possibile passare qualsiasi tipo di dati nella callback filo, perché punta al vuoto, come illustrato nei seguenti esempi:

#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);
}

Quando il codice di cui sopra è compilato ed eseguito, produce i seguenti risultati:

$ g++ -Wno-write-strings test.cpp -lpthread -o test.o
$ ./test.o
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

Collegamento e separazione filo

Siamo in grado di utilizzare le seguenti due funzioni di collegare o thread separati:

pthread_join (threadid, status) 
pthread_detach (threadid) 

pthread_join () subroutine ostacolare il programma chiamante fino a quando il filo threadid specificato termina. Quando si crea un filo, è un attributo definisce se è collegato (abbinabile) o rimovibile (staccato). Definire solo creare un filo che può essere collegato può essere collegato. Se un thread viene creato è definito come separabili, non può mai essere collegato.

Questo esempio dimostra come utilizzare la funzione pthread_join () per attendere per il thread di completamento.

#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;

   // 初始化并设置线程为可连接的(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], NULL, wait, (void *)i );
      if (rc){
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // 删除属性,并等待其他线程
   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);
}

Quando il codice di cui sopra è compilato ed eseguito, produce i seguenti risultati:

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 : 4  ...exiting 
Sleeping in thread 
Thread with id : 3  ...exiting 
Sleeping in thread 
Thread with id : 2  ...exiting 
Sleeping in thread 
Thread with id : 1  ...exiting 
Sleeping in thread 
Thread with id : 0  ...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.