C ++ มัลติเธรด

มัลติเธรดเป็นรูปแบบเฉพาะของการทำงานหลายอย่างพร้อมกันและมัลติทาสกิ้งเป็นคุณลักษณะที่ช่วยให้คอมพิวเตอร์ของคุณสามารถรันโปรแกรมสองโปรแกรมขึ้นไปพร้อมกันได้ โดยทั่วไปการทำงานหลายอย่างพร้อมกันมีสองประเภท ได้แก่ แบบใช้กระบวนการและแบบใช้เธรด

การทำงานหลายอย่างพร้อมกันตามกระบวนการจะจัดการกับการทำงานของโปรแกรมพร้อมกัน การทำงานหลายอย่างพร้อมกันแบบเธรดจะเกี่ยวข้องกับการทำงานพร้อมกันของชิ้นส่วนของโปรแกรมเดียวกัน

โปรแกรมมัลติเธรดประกอบด้วยสองส่วนหรือมากกว่าที่สามารถทำงานพร้อมกันได้ แต่ละส่วนของโปรแกรมดังกล่าวเรียกว่าเธรดและแต่ละเธรดกำหนดเส้นทางการทำงานแยกกัน

C ++ ไม่มีการสนับสนุนในตัวสำหรับแอปพลิเคชันมัลติเธรด แต่ขึ้นอยู่กับระบบปฏิบัติการทั้งหมดในการจัดหาคุณลักษณะนี้

บทช่วยสอนนี้จะถือว่าคุณกำลังทำงานบน Linux OS และเรากำลังจะเขียนโปรแกรม C ++ แบบมัลติเธรดโดยใช้ POSIX POSIX Threads หรือ Pthreads ให้ API ซึ่งมีอยู่ในระบบ POSIX ที่เหมือน Unix เช่น FreeBSD, NetBSD, GNU / Linux, MacOS X และ Solaris

การสร้างเธรด

รูทีนต่อไปนี้ใช้เพื่อสร้างเธรด POSIX -

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

ที่นี่ pthread_createสร้างเธรดใหม่และทำให้สามารถเรียกใช้งานได้ กิจวัตรนี้สามารถเรียกกี่ครั้งก็ได้จากทุกที่ภายในรหัสของคุณ นี่คือคำอธิบายของพารามิเตอร์ -

ซีเนียร์ No พารามิเตอร์และคำอธิบาย
1

thread

ตัวระบุเฉพาะที่ทึบแสงสำหรับเธรดใหม่ที่ส่งคืนโดยรูทีนย่อย

2

attr

อ็อบเจ็กต์แอ็ตทริบิวต์ทึบแสงที่อาจใช้เพื่อตั้งค่าแอ็ตทริบิวต์เธรด คุณสามารถระบุอ็อบเจ็กต์แอ็ตทริบิวต์เธรดหรือค่า NULL สำหรับค่าดีฟอลต์

3

start_routine

รูทีน C ++ ที่เธรดจะดำเนินการเมื่อสร้างขึ้น

4

arg

อาร์กิวเมนต์เดียวที่อาจถูกส่งไปยัง start_routine จะต้องส่งผ่านโดยการอ้างอิงเป็นตัวชี้ประเภทโมฆะ สามารถใช้ NULL ได้หากไม่มีการโต้แย้ง

จำนวนเธรดสูงสุดที่กระบวนการอาจสร้างขึ้นนั้นขึ้นอยู่กับการนำไปใช้งาน เมื่อสร้างแล้วเธรดจะเป็นแบบเดียวกันและอาจสร้างเธรดอื่น ๆ ไม่มีลำดับชั้นโดยนัยหรือการพึ่งพาระหว่างเธรด

การยุติเธรด

มีกิจวัตรต่อไปนี้ที่เราใช้เพื่อยุติเธรด POSIX -

#include <pthread.h>
pthread_exit (status)

ที่นี่ pthread_exitใช้เพื่อออกจากเธรดอย่างชัดเจน โดยปกติรูทีน pthread_exit () จะถูกเรียกหลังจากเธรดทำงานเสร็จสิ้นและไม่จำเป็นต้องมีอยู่อีกต่อไป

หาก main () เสร็จสิ้นก่อนเธรดที่สร้างขึ้นและออกด้วย pthread_exit () เธรดอื่น ๆ จะดำเนินการต่อ มิฉะนั้นจะถูกยกเลิกโดยอัตโนมัติเมื่อ main () เสร็จสิ้น

Example

โค้ดตัวอย่างง่ายๆนี้สร้าง 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

การส่งผ่านอาร์กิวเมนต์ไปยังเธรด

ตัวอย่างนี้แสดงวิธีการส่งผ่านหลายอาร์กิวเมนต์ผ่านโครงสร้าง คุณสามารถส่งผ่านประเภทข้อมูลใดก็ได้ในการเรียกกลับเธรดเนื่องจากชี้ไปที่โมฆะตามที่อธิบายในตัวอย่างต่อไปนี้

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