Download free for 30 days
Sign in
Upload
Language (EN)
Support
Business
Mobile
Social Media
Marketing
Technology
Art & Photos
Career
Design
Education
Presentations & Public Speaking
Government & Nonprofit
Healthcare
Internet
Law
Leadership & Management
Automotive
Engineering
Software
Recruiting & HR
Retail
Sales
Services
Science
Small Business & Entrepreneurship
Food
Environment
Economy & Finance
Data & Analytics
Investor Relations
Sports
Spiritual
News & Politics
Travel
Self Improvement
Real Estate
Entertainment & Humor
Health & Medicine
Devices & Hardware
Lifestyle
Change Language
Language
English
Español
Português
Français
Deutsche
Cancel
Save
Submit search
EN
Uploaded by
KIMVR1
353 views
Multi threaded programming in c and c++ 2021-09-03
Multi-Threaded Programming by RAWAT SIRIPOKARPIROM
Engineering
◦
Read more
0
Save
Share
Embed
Embed presentation
1
/ 19
2
/ 19
3
/ 19
4
/ 19
5
/ 19
6
/ 19
7
/ 19
8
/ 19
9
/ 19
10
/ 19
11
/ 19
12
/ 19
13
/ 19
14
/ 19
15
/ 19
16
/ 19
17
/ 19
18
/ 19
19
/ 19
More Related Content
PPTX
React Native
by
Software Infrastructure
PDF
Cours php & Mysql - 1ére partie
by
kadzaki
PDF
Tweaking the interactive grid
by
Roel Hartman
PDF
2 ways to get total sum of interactive grid column oracle apex ontoor blogs
by
sulimankareem
PPT
Presentation Symfony
by
Jeremy Gachet
PDF
Web develop in flask
by
Jim Yeh
PDF
PL/Python: Programando em Python no PostgreSQL
by
Juliano Atanazio
PDF
Gérer sa facturation avec Access (MAJ du tutoriel Créer une facture avec Access)
by
Votre Assistante
React Native
by
Software Infrastructure
Cours php & Mysql - 1ére partie
by
kadzaki
Tweaking the interactive grid
by
Roel Hartman
2 ways to get total sum of interactive grid column oracle apex ontoor blogs
by
sulimankareem
Presentation Symfony
by
Jeremy Gachet
Web develop in flask
by
Jim Yeh
PL/Python: Programando em Python no PostgreSQL
by
Juliano Atanazio
Gérer sa facturation avec Access (MAJ du tutoriel Créer une facture avec Access)
by
Votre Assistante
What's hot
PDF
Introduction à React
by
Thibault Martinez
PDF
Quick flask an intro to flask
by
juzten
PPTX
Ppt Of Peoplesoft
by
saurabhtiwari
PPT
Oracle Forms :Window and Canvases
by
Sekhar Byna
PPTX
Application engine
by
JAYAARC
PDF
My web application in 20 minutes with Telosys
by
Laurent Guérin
PPTX
JavaScript Event Loop
by
Designveloper
PPT
Cours php
by
csskaled
PDF
Tp java ee.pptx
by
Eric Bourdet
PDF
Gestion de la production de films promotionnels - Projet en bases de données
by
Cédric Mouats
PDF
Cómo instalar y configurar radmin
by
nelson rodriguez huallpa
PDF
Cours SE Principes et fonctionnement de système d’exploitation - IPSET.pdf
by
MedBechir
PDF
Stockage de données dans Android : Fichiers
by
Lilia Sfaxi
PPT
Cours JavaScript.ppt
by
PROFPROF11
PDF
Langage C++
by
Anass SABANI
PDF
API for Beginners
by
Sébastien Saunier
PDF
Python Regular Expressions
by
BMS Institute of Technology and Management
PDF
Declarative UIs with Jetpack Compose
by
Ramon Ribeiro Rabello
PPTX
C# REST API
by
Simplilearn
PDF
Jetpack compose
by
LutasLin
Introduction à React
by
Thibault Martinez
Quick flask an intro to flask
by
juzten
Ppt Of Peoplesoft
by
saurabhtiwari
Oracle Forms :Window and Canvases
by
Sekhar Byna
Application engine
by
JAYAARC
My web application in 20 minutes with Telosys
by
Laurent Guérin
JavaScript Event Loop
by
Designveloper
Cours php
by
csskaled
Tp java ee.pptx
by
Eric Bourdet
Gestion de la production de films promotionnels - Projet en bases de données
by
Cédric Mouats
Cómo instalar y configurar radmin
by
nelson rodriguez huallpa
Cours SE Principes et fonctionnement de système d’exploitation - IPSET.pdf
by
MedBechir
Stockage de données dans Android : Fichiers
by
Lilia Sfaxi
Cours JavaScript.ppt
by
PROFPROF11
Langage C++
by
Anass SABANI
API for Beginners
by
Sébastien Saunier
Python Regular Expressions
by
BMS Institute of Technology and Management
Declarative UIs with Jetpack Compose
by
Ramon Ribeiro Rabello
C# REST API
by
Simplilearn
Jetpack compose
by
LutasLin
Similar to Multi threaded programming in c and c++ 2021-09-03
PPT
Operating System Chapter 5
by
Nuth Otanasap
PPT
Operating System Chapter 4
by
Nuth Otanasap
PPT
Ch06th
by
Nuth Otanasap
PDF
คำศัพท์ที่ควรทราบ
by
ossaga
PDF
Producer and Consumer problem
by
Bhuridech Sudsee
PPT
Java Programming [12/12] : Thread
by
IMC Institute
PDF
การจัดการโปรเซส
by
CC Nakhon Pathom Rajabhat University
PPT
Os ch02
by
Kru Aon Cheme
PPT
Os ch02
by
Kru Aon Cheme
PPT
Operating System Chapter 1
by
Nuth Otanasap
PPT
4 ca-process structure
by
krissapat
PDF
ความหมายของโปรแกรมคอมพิวเตอร์
by
tugkrung
PDF
ความหมายของโปรแกรมคอมพิวเตอร์
by
tugkrung
PPT
งานนำเสนอ1
by
ninewnilubon
PDF
The bounded buffer
by
Bhuridech Sudsee
PPT
Operating System Chapter 3
by
Nuth Otanasap
PDF
การเขียนโปรแกรม Dev c++
by
Naowarat Jaikaroon
PDF
CPU Scheduling
by
Hi Nana
PDF
Pttออ้ม
by
aomtoy
PDF
Pttออ้ม
by
aomtoy
Operating System Chapter 5
by
Nuth Otanasap
Operating System Chapter 4
by
Nuth Otanasap
Ch06th
by
Nuth Otanasap
คำศัพท์ที่ควรทราบ
by
ossaga
Producer and Consumer problem
by
Bhuridech Sudsee
Java Programming [12/12] : Thread
by
IMC Institute
การจัดการโปรเซส
by
CC Nakhon Pathom Rajabhat University
Os ch02
by
Kru Aon Cheme
Os ch02
by
Kru Aon Cheme
Operating System Chapter 1
by
Nuth Otanasap
4 ca-process structure
by
krissapat
ความหมายของโปรแกรมคอมพิวเตอร์
by
tugkrung
ความหมายของโปรแกรมคอมพิวเตอร์
by
tugkrung
งานนำเสนอ1
by
ninewnilubon
The bounded buffer
by
Bhuridech Sudsee
Operating System Chapter 3
by
Nuth Otanasap
การเขียนโปรแกรม Dev c++
by
Naowarat Jaikaroon
CPU Scheduling
by
Hi Nana
Pttออ้ม
by
aomtoy
Pttออ้ม
by
aomtoy
Multi threaded programming in c and c++ 2021-09-03
1.
Multi-Threaded Programming การเขียนโปรแกรมให้ทำงานแบบมัลติเทรดด้วยภาษา C/C++ การทำงานแบบมัลติเทรด แอปพลิเคชัน
(Application) หรือโปรแกรมในระดับผู้ใช้(User-Level Program) ที่ทำงานภายใต้การจัดการของระบบ ปฏิบัติการ Linux จะเรียกว่า "โปรเซส" (Process) หลาย ๆ โปรเซสสามารถทำงานได้อิสระจากกัน ดังนั้นจึงเป็นการ ทำงานแบบหลายโปรเซส (Multi-Processing) โปรเซสก็สามารถสร้างโปรเซสอื่นอีกให้เริ่มต้นทำงานใหม่ได้เช่นกัน เป็นความสัมพันธ์ระหว่าง โปรเซสที่สร้าง (Parent Process) กับโปรเซสที่ถูกสร้าง (Child Process) และเรียกขั้นตอนนี้ว่า Process forking / spawning ในแต่ละโปรเซสก็สามารถแบ่งออกเป็นการทำงานย่อย ๆ เรียกว่า "เทรด" (Thread) มีหลายเทรดทำงานได้ไปได้พร้อม ๆ กัน (Multi-Threading) หรือเรียกว่า Concurrency ซึ่งจะมีประโยชน์และช่วยเพิ่มประสิทธิภาพในการทำงานของ ระบบเนื่องจากคอมพิวเตอร์มีตัวประมวลผลมากกว่าหนึ่งตัวได้(Multi-Processor / Multi-Core CPU) และเป็นการ เพิ่มระดับการทำงานแบบขนานกันในระดับฮาร์ดแวร์ (Parallel Processing) การทำงานแบบหลายเทรดนั้น สามารถใช้งานได้ทั้งแบบมีซีพียูเดียว (Single-CPU) โดยการแบ่งช่วงเวลากันทำงาน ระหว่างเทรด ให้ดูเสมือนว่าทำงานไปได้พร้อม ๆ กัน หรือใช้กับการทำงานของซีพียูที่มีหลายแกน (Multi-Core CPU) ก็ได้ แต่ถ้ามีการนำคอมพิวเตอร์มาใช้งานร่วมกันในระบบเครือข่ายที่เชื่อมต่อกันด้วยความเร็วสูง และเขียนโปรแกรมเพื่อให้ ทำงานร่วมกัน ให้เป็นส่วนหนึ่งของแอปพลิเคชันเดียวกัน ก็จะเรียกรูปแบบนี้ว่า การประมวลผลแบบกระจาย (Distributed Processing / Computing) เราสามารถเขียนโปรแกรมเพื่อให้มีมากกว่าหนึ่งเทรด และสามารถทำงานได้อิสระจากกัน แต่บางกรณีก็ต้องมีการสื่อสาร กันระหว่างเทรด หรือรอจังหวะการทำงานซึ่งกันและกัน (Inter-Thread Communication & Synchronization) ถ้าเปรียบเทียบการทำงานระหว่างโปรเซสกับเทรดโดยการจัดการของระบบปฏิบัติการ (OS) การสร้างเทรดขึ้นมาใหม่นั้น มีขั้นตอนและการใช้ทรัพยากรของระบบ (หรือเรียกว่า Overhead) น้อยกว่าการสร้างโปรเซส เช่น เทรดที่ถูกสร้างขึ้น ภายใต้โปรเซสเดียวกันจะแชร์การใช้หน่วยความจำเดียวกัน แต่ถ้าเป็นการสร้างโปรเซสใหม่ จะต้องมีการแยกหน่วย ความจำในการใช้งานระหว่างโปรเซสเหล่านั้น ในกรณีที่เขียนโปรแกรมด้วยภาษา C/C++ สำหรับ Linux ก็สามารรถใช้ไลบรารีชื่อว่า POSIX Pthreads (ตามมาตรฐาน (POSIX.1-2001 และ POSIX.1-2008) สำหรับการสร้างและจัดการทำงานของเทรดได้ตัวอย่างฟังก์ชันการทำงานที่ เกี่ยวกับเทรด เช่น การสร้างเทรดใหม่ (Thread creation) การจบการทำงานของเทรด (Thread termination) การทำงานแบบรอจังหวะกันระหว่างเทรด (Thread synchronization) การจัดลำดับการทำงานของเทรด (Thread scheduling) การจัดการข้อมูลของเทรดและปฏิสัมพันธ์กับโปรเซส (Thread data management and process interaction) ในกรณีที่เขียนโปรแกรมด้วยภาษาอื่น อย่างเช่น Java หรือ Python ก็มีไลบรารีให้ใช้งานสำหรับการทำงานแบบมัลติ เทรดเช่นกัน การทำงานของเทรดภายใต้โปรเซสเดียวกัน มีการแชร์หรือใช้ทรัพยากรร่วมกันระหว่างเทรด แต่ก็มีสิ่งที่แต่ละเทรดนั้น ใช้งานแยกกัน เช่น
2.
Thread ID เป็นหมายเลขที่แตกต่างกันและใช้ระบุเทรดแต่ละเทรด Thread
priority เป็นระดับความสำคัญของเทรดและใช้ในการจัดลำดับการทำงานของเทรด Set of registers, stack pointer (SP) เป็นหน่วยความจำที่ใช้เก็บค่าของรีจิสเตอร์ต่าง ๆ ของซีพียูและเกี่ยวข้อง กับการทำงานของเทรด เนื่องจากมีการแชร์การใช้งานซีพียูร่วมกัน ข้อมูลเหล่านี้จะถูกจัดเก็บลงในหน่วยความจำที่ เรียกว่า Stack ของแต่ละเทรด ดังนั้นจึงต้องมีตัวระบุหรือชี้ตำแหน่งบนสุดของ Stack ดังกล่าว Stack for local variables, return addresses เป็นหน่วยความจำแบบ Stack ที่ใช้เก็บข้อมูลในขณะที่เทรด กำลังทำงาน เช่น เก็บค่าตัวแปรภายในเมื่อมีการเรียกใช้ฟังก์ชันและจบการทำงานของฟังก์ชัน เป็นต้น เนื่องจากในการทำงานแบบมัลติเทรด จะต้องมีการแบ่งเวลาหรือสลับเวลาในการทำงานกันระหว่างเทรด ดังนั้นจึงต้องมี การบันทึกสถานะการทำงานของเทรดและเรียกคืนกลับมาทำงานต่อ การสลับการทำงานของเทรด ก็เรียกว่า Thread Context Switching ถ้าจะลองเขียนโค้ดโดยใช้ภาษา C++ ก็มีความแตกต่างจากโค้ดภาษา C ออกไปบ้าง แต่ก็สามารถใช้คำสั่งหรือฟังก์ชัน ของไลบรารี POSIX Pthreads ได้เช่นกัน หรือจะใช้คลาส std::thread (สำหรับเวอร์ชัน C++11 C++14 และ C++17) นอกจากนั้นแล้วถ้าลองสืบค้นในอินเทอร์เน็ต จะพบว่า มีนักพัฒนาซอฟต์แวร์ได้สร้างคลาส C++ ทำหน้าที่เป็นตัวครอบ การใช้งานคำสั่งต่าง ๆ ของ POSIX Pthreads ไว้เป็นตัวอย่างหรือนำไปทดลองใช้งานได้โดยแชร์โค้ดไว้ใน Github เป็นต้น ตัวอย่างโค้ด C สาธิตการใช้งาน Pthreads เนื้อหาในส่วนนี้นำเสนอตัวอย่างการเขียนโค้ดภาษา C โดยใช้ไลบรารี POSIX Pthreads สาธิตการทำงานแบบมัลติ เทรดในรูปแบบต่าง ๆ ตัวอย่างที่ 1: Thread Creation โค้ดตัวอย่างแรกนี้ สาธิตการเขียนโปรแกรม เพื่อสร้างเทรดจำนวน 2 เทรด (Thread 1 และ Thread 2) โดยใช้คำสั่ง pthread_create(...) ซึ่งจะให้ค่ากลับคืนเป็น 0 ถ้าสร้างเทรดใหม่ได้สำเร็จ ในขั้นตอนการทำงานของเทรด จะต้องมีการสร้างฟังก์ชันตามรูปแบบที่กำหนดไว้โดย POSIX Pthreads ดังนี้ int pthread_create( pthread_t *thread, 1 const pthread_attr_t *attr, 2 void *(*start_routine)(void*), 3 void *arg ); 4 ในตัวอย่างนี้ใช้ชื่อฟังก์ชัน thread_entry_func(...) สำหรับ Thread Start Routine และเป็นตัวกำหนดฟังก์ชันการ ทำงานของเทรด ทั้งสองเทรดในตัวอย่างนี้ มีการใช้ฟังก์ชันดังกล่าวร่วมกัน และเมื่อสร้างเทรดขึ้นมาแล้ว จะใช้ตัวแปรที่ มีชนิดข้อมูลเป็น pthread_t เป็นตัวอ้างอิงแต่ละเทรด ในตัวอย่างนี้ฟังก์ชันนี้รับค่าอาร์กิวเมนต์มาเป็นพอยน์เตอร์แบบ (void *) แต่แปลงให้เป็นเลขจำนวนเต็มชนิด long เพื่อ ใช้จำแนกว่า เป็นเทรดหมายเลขใด เมื่อทำคำสั่งต่าง ๆ ของฟังก์ชันนี้ จะมีการรอเวลาให้ผ่านไปโดยใช้คำสั่ง sleep(...) ระยะเวลาในการรอหน่วยเป็นวินาที จะได้จากการใช้คำสั่ง rand(...) เพื่อสุ่มค่าตัวเลขจำนวนเต็ม โดยกำหนดให้มีค่าอยู ในช่วง 1..10 วินาที เมื่อรอเวลาตามที่กำหนดไว้แล้ว การทำงานของเทรดจึงจบลง (แต่ละเทรดจะใช้เวลารอไม่เหมือน กัน เพราะอาจสุ่มเลขได้ค่าต่างกัน ดังนั้นจึงจบการทำงานไม่พร้อมกัน) การทำงานของโปรแกรมนี้ เมื่อได้สร้างเทรดใหม่ทั้งสองแล้ว จากนั้นจะต้องรอให้เทรดทั้งสองจบการทำงานก่อน จึงจะ จบการทำงานของโปรแกรม การรอคอยให้เทรดของโปรเซสจบการทำงานนั้น จะต้องใช้คำสั่ง pthread_join(...) ดังนั้น จึงเป็นการเรียกฟังก์ชันแบบ Blocking Call หรือ รอไปแบบไม่มีเวลาจำกัดจนกว่าเงื่อนไขจะเป็นจริง
3.
// $ gcc
-Wall main.c -o main -lpthread 1 2 #include <stdio.h> 3 #include <stdlib.h> // for srand(), rand() 4 #include <unistd.h> // for sleep(), usleep() 5 #include <pthread.h> // the header file for the pthread lib 6 7 void *thread_entry_func( void *arg ) { 8 long id = (long)arg; 9 printf( "Thread started: %ldn", id ); 10 // sleep for some seconds (randomized between 1..10) 11 sleep( 1 + (rand() % 10) ); 12 printf( "Thread finished: %ldn", id ); 13 return NULL; 14 } 15 16 int main( int argc, char *argv[] ) { 17 int retval; 18 pthread_t thread1, thread2; 19 20 // initialize the pseudorandom generator with a seed 21 srand( time(NULL) ); 22 23 // create Thread 1 24 retval = pthread_create( 25 &thread1 /*used to identify thread*/, 26 NULL /*default attributes*/, 27 thread_entry_func /*start routine*/, 28 (void*) 1 /*thread argument*/ ); 29 printf( "Create thread 1: %sn", 30 retval ? "FAILED" : "OK" ); 31 32 // create Thread 2 33 retval = pthread_create( 34 &thread2 /*used to identify thread*/, 35 NULL /*default attributes*/, 36 thread_entry_func /*start routine*/, 37 (void*) 2 /*thread argument*/ ); 38 printf( "Create thread 2: %sn", 39 retval ? "FAILED" : "OK" ); 40 41 usleep( 10000 /*usec*/ ); // sleep for 10msec 42 43 // wait until thread 1 and 2 are finished. 44 printf( "Waiting for threads to be finishedn" ); 45 if (thread1) { 46 pthread_join( thread1, NULL ); // wait for thread 1 47 } 48 if (thread2) { 49 pthread_join( thread2, NULL ); // wait for thread 2 50 } 51 printf( "Done...nn" ); 52 return 0; 53 } 54 รูปต่อไปนี้แสดงตัวอย่างการทำคำสั่งแบบ Command line เพื่อคอมไพล์โค้ดชื่อ main.c ที่มีโค้ดในตัวอย่างให้เป็น ไฟล์ executable ที่มีชื่อว่า main จากนั้นจึงรันโปรแกรมดังกล่าว
4.
ถ้าต้องการจะกำหนดคุณสมบัติของเทรด (pthread_attr_t) ที่จะถูกสร้างขึ้นใหม่โดยใช้คำสั่ง
pthread_attr_init(...) ก็มี ตัวอย่างดังนี้ เช่น การกำหนดให้เทรดมีสถานะเป็น joinable และการเพิ่มขนาดของ Stack สำหรับการทำงานของเทรด เป็นต้น // $ gcc -Wall main.c -o main -lpthread 1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> // for sleep(), usleep() 5 #include <pthread.h> // the header file for the pthread lib 6 7 void *thread_entry_func( void *arg ) { 8 printf( "Thread is active.n" ); 9 return NULL; 10 } 11 12 int main( int argc, char *argv[] ) { 13 int retval; 14 size_t stack_size; 15 pthread_attr_t attr; 16 pthread_t thread; 17 18 // create a thread attribute object 19 retval = pthread_attr_init(&attr); 20 if (retval) { 21 printf( "Error while creating thread attribute!n" ); 22 exit(1); 23 } 24 // use a joinable thread 25 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); 26 // get the default stack size 27 pthread_attr_getstacksize( &attr, &stack_size ); 28 printf( "Default thread stack size: %ldn", stack_size ); 29 // set the stack size (use a larger value, say 4x) 30 pthread_attr_setstacksize( &attr, 4*stack_size ); 31 32 // create Thread 33 retval = pthread_create( 34 &thread, &attr, thread_entry_func, NULL ); 35 printf( "Create thread: %sn", 36 retval ? "FAILED" : "OK" ); 37 38 sleep(1); 39 // get the thread stack size 40 pthread_attr_getstacksize( &attr, &stack_size ); 41 printf( "Thread stack size: %ldn", stack_size ); 42 pthread_attr_destroy( &attr ); // destroy attribute 43 44 if (thread) { 45 pthread_join( thread, NULL ); // wait for thread 46
5.
} 47 printf( "Done...nn" ); 48 return
0; 49 } 50 ถัดไปเป็นการสร้างเทรดตามจำนวนที่กำหนดไว้โดย NUM_THREADS แต่มีลักษณะการทำงานเหมือนโค้ดในตัวอย่าง แรก #include <stdio.h> 1 #include <stdlib.h> // for srand(), rand() 2 #include <unistd.h> // for sleep(), usleep() 3 #include <pthread.h> // the header file for the pthread lib 4 5 #define NUM_THREADS (10) 6 7 void *thread_entry_func( void *arg ) { 8 long id = (long)arg; 9 printf( "Thread started: %ld (0x%08lX)n", id, pthread_self() ); 10 // sleep for some seconds (randomized between 1..10) 11 sleep( 1 + (rand() % 10) ); 12 printf( "Thread finished: %ldn", id ); 13 return NULL; 14 } 15 16 int main( int argc, char *argv[] ) { 17 int retval; 18 pthread_t threads[ NUM_THREADS ]; 19 20 // initialize the pseudorandom generator with a seed 21 srand( time(NULL) ); 22 23 // create a number of threads 24 for ( int i=0; i < NUM_THREADS; i++ ) { 25 long id = (i+1); // used as thread argument 26 retval = pthread_create( 27 &threads[i], NULL, 28 thread_entry_func, 29 (void*) id ); 30 printf( "Create thread %ld: %sn", id, 31 retval ? "FAILED" : "OK" ); 32 if ( retval ) { // thread creation error 33 printf( "Program exited...n" ); 34 exit(1); 35 } 36 } 37 38 usleep( 1000 /*usec*/ ); // sleep for 1msec before proceeding 39 40 // wait until all threads are finished. 41 printf( "Waiting for all threads to be finishedn" ); 42 for ( int i=0; i < NUM_THREADS; i++ ) { 43 pthread_join( threads[i], NULL ); // wait for thread 44 } 45 printf( "Done...nn" ); 46 return 0; 47 } 48 ตัวอย่างที่ 2: Binary Semaphore โค้ดในตัวอย่างนี้สาธิตการใช้งานสิ่งที่เรียกว่า "เซมาฟอร์แบบไบนารี" (Binary Semaphore) เพื่อใช้ส่งสัญญาณสื่อสาร กันระหว่างเทรด เช่น ให้เทรดหนึ่งรอสัญญาณจากอีกเทรดหนึ่ง หรือในกรณีที่จะต้องมีการใช้ทรัพยากรร่วมกัน คำสั่งที่เกี่ยวข้องกับการใช้งานเซมาฟอร์แบบไบนารีของ POSIX Pthreads มีดังนี้
6.
sem_init(...) ตั้งค่าเริ่มต้นของตัวนับและเปิดใช้งานเซมาฟอร์ sem_wait(..) รอการใช้งานเซมาฟอร์
ถ้าได้ให้ลดค่าลงจาก 1 เป็น 0 แต่ถ้ายังไม่ได้ให้รอไปก่อน sem_post(...) เพิ่มค่าเซมาฟอร์ให้เป็น 1 ทันทีโดยไม่ต้องรอ sem_destroy(...) เลิกใช้งานเซมาฟอร์ เซมาฟอร์แบบไบนารีจะมีค่าเริ่มต้นเป็น 1 เมื่อมีการเข้าใช้งานโดยเทรดก็จะลดค่าลงเป็น 0 โดยการทำคำสั่ง sem_wait(...) แต่ถ้ามีค่าเป็น 0 แล้วและมีเทรดใดต้องการใช้งาน จะต้องรอไปก่อน เมื่อใช้งานเซมาฟอร์แล้วก็ต้องเพิ่ม ค่าให้กลับคืนเป็น 1 ด้วยคำสั่ง sem_post(...) ข้อสังเกต: ถ้าให้ตัวนับของเซมาฟอร์มีค่าเริ่มต้นมากกว่า 1 เราจะเรียกว่า "เซมาฟอร์แบบนับ" (Counting Semaphore) // $ gcc -Wall main.c -o main -lpthread 1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> // for sleep(), usleep() 5 #include <pthread.h> // the header file for the pthread lib 6 #include <semaphore.h> 7 8 #define NUM_THREADS (10) 9 10 // global variable 11 sem_t semaphore; 12 13 void *thread_entry_func( void *arg ) { 14 long id = (long)arg; 15 sleep(1); 16 sem_wait(&semaphore); // acquire the semaphore 17 printf( "Thread #%ld is active.n", id ); 18 sem_post(&semaphore); // release the semaphore 19 return NULL; 20 } 21 22 int main( int argc, char *argv[] ) { 23 int retval; 24 pthread_t threads[ NUM_THREADS ]; 25 26 // create a binary semaphore 27 sem_init( &semaphore, 0, 1 /*initial value*/ ); 28 29 // create Threads 30 for (int i=0; i < NUM_THREADS; i++) { 31 retval = pthread_create( 32 &threads[i], NULL, 33 thread_entry_func, 34 (void*)(i+1L) ); 35 printf( "Create thread: %sn", 36 retval ? "FAILED" : "OK" ); 37 if (retval) { 38 exit(1); 39 } 40 } 41 sleep(1); 42 43 for (int i=0; i < NUM_THREADS; i++) { 44 if (threads[i]) { 45 pthread_join( threads[i], NULL ); // wait for thread 46 } 47 } 48 sem_destroy( &semaphore ); // destroy semaphore 49 printf( "Done...nn" ); 50 return 0; 51 } 52
7.
ตัวอย่างที่ 3: Producer-Consumer การทำงานร่วมกันระหว่างเทรดตามรูปแบบที่เรียกว่า
Producer-Consumer Pattern คือ ให้มีเทรดหนึ่งทำหน้าที่สร้าง ข้อมูล (Producer) แล้วส่งต่อให้อีกเทรดหนึ่ง (Consumer) แต่จะต้องมีการรอจังหวะกัน (Inter-Thread Synchronization) เช่น เทรดที่สร้างข้อมูลจะต้องรอให้อีกเทรดหนึ่งรับข้อมูลไปใช้ก่อนที่จะสร้างข้อมูลลำดับถัดไป มิ เช่นนั้นก็อาจเกิดปัญหาได้เรียกว่า Race Condition ดังนั้นในกรณีนี้ จึงจะใช้สิ่งที่เรียกว่า Mutex (Mutual Exclusive) ซึ่งทำหน้าที่เป็นเสมือนล็อคป้องกัน (Lock) เพื่อเข้า ใช้งานทรัพยากรร่วม หรือเพื่อการจำกัดสิทธิ์การเข้าถึงทรัพยากรร่วมระหว่างเทรด ยกตัวอย่างเช่น ถ้ามีหลายเทรด และ ต้องการให้ในช่วงเวลาใดเวลาหนึ่ง มีเพียงเทรดเดียวเท่านั้นที่เข้าใช้ทรัพยากรร่วมได้ ถ้าเทรดใดจะเข้าถึงตัวแปรที่แชร์ใช้งานร่วมกัน จะต้องพยายามใส่ล็อคเพื่อป้องกันมิให้เทรดอื่นเข้ามาใช้งานได้และเมื่อ เสร็จแล้ว ก็ต้องปลดล็อคดังกล่าว การทำงานของ Mutex มีลักษณะคล้ายกับเซมาฟอร์แบบไบนารี แต่ก็มีความแตกต่างกัน เช่น หลักการทำงานแบบมี เจ้าของ (Ownership) และ Recursive Mutex คำสั่งที่เกี่ยวกับการใช้งาน Mutex Lock (pthread_mutex_t) ที่สำคัญได้แก่ pthread_mutex_init(...) เพื่อสร้างและเริ่มต้นใช้งาน mutex pthread_mutex_lock(...) เพื่อปิดล็อคของ mutex แต่ถ้าไม่ได้จะบล็อกการทำงานของเทรดไปจนกว่าจะปิดล็อค ได้ pthread_mutex_trylock(...) เพื่อลองดูว่าสามารถปิดล็อคของ mutex ได้หรือไม่ ถ้าไม่ได้ก็จะไม่มีการบล็อกการ ทำงานของเทรด pthread_mutex_unlock(...) เพื่อปลดล็อคของ mutex pthread_destroy(...) เลิกใช้mutex ในตัวอย่างนี้ ตัวแปร message ซึ่งเป็นอาร์เรย์แบบ (char *) สำหรับเก็บข้อความ (String) จะถูกใช้ในการส่งข้อมูล ระหว่างเทรดที่เป็น Producer และ Consumer ดังนั้นจึงถือว่าเป็นส่วนที่เรียกว่า "เขตวิกฤต" (Critical Section) ถ้าจะ เข้าใช้งานตัวแปรนี้จะต้องมีการใช้Mutex Lock ก่อนทุกครั้ง และจะมีการสร้างข้อความทั้งหมด 10 ครั้ง เทรดที่ทำหน้าที่เป็น Producer จะต้องตรวจสอบก่อนว่า ตัวแปร flag เป็น false หรือไม่ จึงจะเขียนข้อความใหม่ลงไป และเทรดที่เป็น Consumer จะต้องตรวจสอบค่าของตัวแปรนี้เช่นกัน แต่เมื่อนำข้อความไปใช้แสดงผลแล้วเปลี่ยนค่า ของตัวแปร flag เป็น true #include <stdio.h> 1 #include <stdlib.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <pthread.h> 6 7 // global variables 8 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 9 static char message[32]; // shared variable 10 static bool running = true; 11 static bool flag = false; 12 13 void *producer_func( void *arg ) { 14 int cnt = 1; 15 while (cnt <= 10) { 16 // blocking call 17 pthread_mutex_lock( &lock ); 18 if (!flag) { 19 snprintf( message, sizeof(message), 20 "hello #%d", cnt++ ); 21 printf( "Producer> %sn", message ); 22 flag = true; 23
8.
} 24 pthread_mutex_unlock(
&lock ); 25 usleep( 1000 + (rand() % 1000) ); 26 } 27 return NULL; 28 } 29 30 void *consumer_func( void *arg ) { 31 while (running) { 32 // blocking call 33 pthread_mutex_lock( &lock ); 34 if ( flag ) { 35 printf( "Consumer> %snn", message ); 36 message[0] = '0'; // clear message string 37 flag = false; 38 usleep( (rand() % 1000)*1000 ); 39 } 40 pthread_mutex_unlock( &lock ); 41 usleep(1); 42 } 43 return NULL; 44 } 45 46 int main( int argc, char *argv[] ) { 47 int retval; 48 pthread_t producer_thread, consumer_thread; 49 50 // initialize the pseudorandom generator with a seed 51 srand( time(NULL) ); 52 53 // clear message buffer 54 memset( message, 0, sizeof(message) ); 55 56 // create a mutex lock 57 if ( pthread_mutex_init( &lock, NULL ) ) { 58 printf( "Mutex init failed!n" ); 59 exit(1); 60 } 61 62 // create producer and consumer threads 63 retval = pthread_create( 64 &producer_thread, NULL, 65 producer_func, (void*) NULL ); 66 if (retval) { 67 printf( "Create producer thread failed!n" ); 68 exit(1); 69 } 70 retval = pthread_create( 71 &consumer_thread, NULL, 72 consumer_func, (void*) NULL ); 73 if (retval) { 74 printf( "Create consumer thread failed!n" ); 75 exit(1); 76 } 77 78 usleep( 10000 /*usec*/ ); // sleep for 10msec before proceeding 79 80 // wait for producer thread 81 pthread_join( producer_thread, NULL ); 82 running = false; // change running flag to false 83 pthread_cancel( consumer_thread ); // cancel consumer thread 84 pthread_join( consumer_thread, NULL ); // wait for consumer thread 85 pthread_mutex_destroy( &lock ); // destroy mutex lock 86 printf( "Done...nn" ); 87 return 0; 88 } 89 ในตัวอย่างนี้ เทรด Producer จะจบการทำงานเอง เมื่อได้สร้างข้อความตามจำนวนที่กำหนดไว้ครบแล้ว แต่สำหรับการ ทำงานของเทรด Consumer จะมีการใช้คำสั่ง pthread_cancel(...) เพื่อขอให้จบการทำงานหลังจากนั้น
9.
ถ้าจะลองเปลี่ยนมาใช้คำสั่ง pthread_mutex_trylock(...) สำหรับฟังก์ชันการทำงานของเทรด
ก็มีตัวอย่างโค้ดดังนี้ void *producer_func( void *arg ) { 1 int cnt = 1; 2 while (cnt <= 10) { 3 // blocking call 4 while( pthread_mutex_trylock( &lock ) ) { 5 usleep( 1000 ); 6 } 7 if (!flag) { 8 snprintf( message, sizeof(message), 9 "hello #%d", cnt++ ); 10 printf( "Producer> %sn", message ); 11 flag = true; 12 } 13 pthread_mutex_unlock( &lock ); 14 usleep( 1000 + (rand() % 1000) ); 15 } 16 return NULL; 17 } 18 19 void *consumer_func( void *arg ) { 20 while (running) { 21 // blocking call 22 while( pthread_mutex_trylock( &lock ) ) { 23 usleep( 1000 ); 24 } 25 if ( flag ) { 26 printf( "Consumer> %snn", message ); 27 message[0] = '0'; // clear message string 28 flag = false; 29 usleep( (rand() % 1000)*1000 ); 30 } 31 pthread_mutex_unlock( &lock ); 32 usleep(1); 33 } 34 return NULL; 35 } 36 ตัวอย่างที่ 4: การใช้ Condition Variable ถ้าต้องการให้เทรดหยุดรอ (Waiting / Blocked) เหตุการณ์ตามเงื่อนไขที่กำหนดไว้จนกว่าเงื่อนไขจะเป็นจริง แล้วจึง ให้ทำงานต่อไป ในสถานการณ์เช่นนี้ เราสามารถใช้ตัวแปรประเภทหนึ่งที่เรียกว่า "ตัวแปรเงื่อนไข" (Condition Variable) และการทำให้เงื่อนไขเป็นจริงได้นั้น จะต้องมีการส่งสัญญาณ (Signaling) จากเทรดอื่นมา ตัวแปรเงื่อนไขจึง เป็นอีกวิธีการหนึ่งในการสื่อสารกันระหว่างเทรด (Inter-Thread Communication) ในไลบรารีของ POSIX Pthread ก็มีคำสั่งสำหรับการใช้งาน Condition Variable (ชนิดข้อมูล pthread_cond_t) โดย จะต้องใช้ร่วมกับ Mutex (ชนิดข้อมูล pthread_mutex_t) และคำสั่งที่เกี่ยวข้องได้แก่ pthread_cond_init(...) สร้างและเริ่มต้นใช้งานตัวแปรเงื่อนไข pthread_cond_wait(...) รอจนกว่าตัวแปรเงื่อนไขจะเป็นจริง pthread_cond_timedwait(...) รอจนกว่าตัวแปรเงื่อนไขจะเป็นจริง แต่มีระยะเวลาจำกัดในการรอ pthread_cond_signal(...) ส่งสัญญาณไปยังเทรดที่รออยู่ เพื่อระบุว่าตัวแปรเงื่อนไขเป็นจริง และเทรดที่รอ เงื่อนไขอยู่จะทำงานต่อได้ pthread_cond_broadcast(...) ส่งสัญญาณไปยังทุกเทรดที่รออยู่ เพื่อระบุว่าตัวแปรเงื่อนไขเป็นจริง pthread_cond_destroy(...) เลิกใช้ตัวแปรแบบเงื่อนไข ตัวอย่างนี้สาธิตการสร้างเทรดขึ้นมาใหม่ และให้เทรดดังกล่าวรอให้มีการส่งสัญญาณมาจากเทรดหลักในฟังก์ชัน main() และจะเพิ่มค่าตัวนับของตัวแปรภายในและแสดงข้อความตัวเลขดังกล่าว การส่งสัญญาณสำหรับตัวแปรเงื่อนไข ในตัวอย่างจะเกิดขึ้นทั้งหมด 10 ครั้ง
10.
#include <stdio.h> 1 #include <stdlib.h> 2 #include
<unistd.h> 3 #include <pthread.h> 4 5 // global variables 6 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 7 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 8 9 void *thread_func( void *arg ) { 10 int ticks = 0; 11 while (1) { 12 pthread_mutex_lock( &mutex ); 13 // wait for signal 14 if ( !pthread_cond_wait( &cond, &mutex ) ) { 15 printf( "ticks: %dn", ++ticks ); 16 } 17 pthread_mutex_unlock( &mutex ); 18 } 19 printf( "Thread exited..n" ); 20 return NULL; 21 } 22 23 int main( int argc, char *argv[] ) { 24 int retval; 25 pthread_t thread; 26 27 // create a mutex lock 28 if ( pthread_mutex_init( &mutex, NULL ) ) { 29 printf( "Mutex init failed!n" ); 30 exit(1); 31 } 32 // create a condition variable 33 if ( pthread_cond_init( &cond, NULL ) ) { 34 printf( "Cond init failed!n" ); 35 exit(1); 36 } 37 // create a thread 38 retval = pthread_create( 39 &thread, NULL, thread_func, (void*) NULL ); 40 if (retval) { 41 printf( "Create a new thread failed!n" ); 42 exit(1); 43 } 44 45 usleep(10); 46 for ( int i=0; i < 10; i++ ) { 47 pthread_mutex_lock( &mutex ); 48 pthread_cond_signal( &cond ); 49 pthread_mutex_unlock( &mutex ); 50 sleep(1); 51 } 52 pthread_cancel( thread ); 53 pthread_join( thread, NULL ); 54 pthread_cond_destroy( &cond ); 55 pthread_mutex_destroy( &mutex ); // destroy mutex lock 56 printf( "Done...nn" ); 57 return 0; 58 } 59 แต่ถ้าจะลองเปลี่ยนมาใช้คำสั่ง pthread_cond_timewait(...) เพื่อให้เทรดสามารถรอเงื่อนไข แต่มีระยะเวลาจำกัด (Timeout) เช่น 1 วินาที แล้วจึงตรวจสอบซ้ำ ก็มีตัวอย่างโค้ดดังนี้ #include <stdio.h> 1 #include <stdlib.h> 2 #include <unistd.h> 3
11.
#include <time.h> 4 #include <pthread.h> 5 6 //
global variables 7 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 8 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 9 static struct timespec ts; 10 11 void *thread_func( void *arg ) { 12 int ticks = 0; 13 int retval; 14 time_t now; 15 while (1) { 16 pthread_mutex_lock( &mutex ); 17 // wait for signal with timeout (1 second) 18 time( &now ); // get current timestamp 19 ts.tv_sec = now + 1; // plus 1 second 20 ts.tv_nsec = 0; 21 retval = pthread_cond_timedwait( &cond, &mutex, &ts ); 22 if ( retval == 0 ) { 23 printf( "ticks: %dn", ++ticks ); 24 } else { // timeout 25 time( &now ); 26 printf( "timeout at %sn", ctime(&now) ); 27 } 28 pthread_mutex_unlock( &mutex ); 29 } 30 printf( "Thread exited..n" ); 31 return NULL; 32 } 33 34 int main( int argc, char *argv[] ) { 35 int retval; 36 pthread_t thread; 37 38 srand( time(NULL) ); 39 40 // create a mutex lock 41 if ( pthread_mutex_init( &mutex, NULL ) ) { 42 printf( "Mutex init failed!n" ); 43 exit(1); 44 } 45 // create a condition variable 46 if ( pthread_cond_init( &cond, NULL ) ) { 47 printf( "Cond init failed!n" ); 48 exit(1); 49 } 50 // create a thread 51 retval = pthread_create( 52 &thread, NULL, thread_func, (void*) NULL ); 53 if (retval) { 54 printf( "Create a new thread failed!n" ); 55 exit(1); 56 } 57 58 usleep(10); 59 for ( int i=0; i < 10; i++ ) { 60 pthread_mutex_lock( &mutex ); 61 pthread_cond_signal( &cond ); 62 pthread_mutex_unlock( &mutex ); 63 usleep( (rand()%2000)*1000 ); 64 } 65 pthread_cancel( thread ); 66 pthread_join( thread, NULL ); 67 pthread_cond_destroy( &cond ); // destroy condition variable 68 pthread_mutex_destroy( &mutex ); // destroy mutex lock 69 printf( "Done...nn" ); 70 return 0; 71 } 72
12.
ถ้าจะลองใช้ตัวแปรเงื่อนไขกับตัวอย่างการสื่อสารกันระหว่างเทรดแบบ Producer-Consumer ก็มีตัวอย่างโค้ดดังนี้ การใช้ตัวแปรเงื่อนไขโดยแยกสำหรับเทรด
Producer และเทรด Consumer แต่มีการใช้Mutex ร่วมกัน เทรด Producer จะต้องรอตัวแปรเงื่อนไข cond_p และมีการส่งสัญญาณจากเทรด Consumer เทรด Consumer จะต้องรอตัวแปรเงื่อนไข cond_c และมีการส่งสัญญาณจากเทรด Producer #include <stdio.h> 1 #include <stdlib.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <time.h> 6 #include <pthread.h> 7 8 // global variables 9 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 10 static pthread_cond_t cond_c = PTHREAD_COND_INITIALIZER; 11 static pthread_cond_t cond_p = PTHREAD_COND_INITIALIZER; 12 static char message[32] = {'0'}; 13 static bool flag = false; 14 15 void *producer_thread_func( void *arg ) { 16 int ticks = 0; 17 while (1) { 18 pthread_mutex_lock( &mutex ); 19 while ( flag ) { // wait for signal from consumer thread 20 pthread_cond_wait( &cond_p, &mutex ); 21 } 22 flag = true; 23 snprintf( message, sizeof(message), "test %d", ++ticks ); 24 printf( "Producer> %sn", message ); 25 // send signal to consumer thread 26 pthread_cond_signal( &cond_c ); 27 pthread_mutex_unlock( &mutex ); 28 usleep( (1+rand()%1000)*1000 ); 29 if (ticks >= 10) break; 30 } 31 printf( "Producer thread exited..n" ); 32 return NULL; 33 } 34 35 void *consumer_thread_func( void *arg ) { 36 while (1) { 37 pthread_mutex_lock( &mutex ); 38 while ( !flag ) { // wait for signal from consumer thread 39 pthread_cond_wait( &cond_c, &mutex ); 40 } 41 flag = false; 42 printf( "Consumer> %snn", message ); 43 message[0] = '0'; 44 // send signal to producer thread 45 pthread_cond_signal( &cond_p ); 46 pthread_mutex_unlock( &mutex ); 47 usleep( (1+rand()%1000)*1000 ); 48 } 49 printf( "Consumer thread exited..n" ); 50 return NULL; 51 } 52 53 int main( int argc, char *argv[] ) { 54 int retval; 55 pthread_t thread_p, thread_c; 56 57 srand( time(NULL) ); 58 59 // create a mutex lock 60 if ( pthread_mutex_init( &mutex, NULL ) ) { 61
13.
printf( "Mutex init
failed!n" ); 62 exit(1); 63 } 64 // create condition variables 65 if ( pthread_cond_init( &cond_p, NULL ) ) { 66 printf( "Cond init failed!n" ); 67 exit(1); 68 } 69 if ( pthread_cond_init( &cond_c, NULL ) ) { 70 printf( "Cond init failed!n" ); 71 exit(1); 72 } 73 // create Producer thread 74 retval = pthread_create( 75 &thread_p, NULL, 76 producer_thread_func, 77 (void*) NULL ); 78 if (retval) { 79 printf( "Create producer thread failed!n" ); 80 exit(1); 81 } 82 // create Consumer thread 83 retval = pthread_create( 84 &thread_c, NULL, 85 consumer_thread_func, 86 (void*) NULL ); 87 if (retval) { 88 printf( "Create consumer thread failed!n" ); 89 exit(1); 90 } 91 92 pthread_join( thread_p, NULL ); 93 pthread_cancel( thread_c ); 94 pthread_join( thread_c, NULL ); 95 pthread_cond_destroy( &cond_p ); 96 pthread_cond_destroy( &cond_c ); 97 pthread_mutex_destroy( &mutex ); 98 printf( "Done...nn" ); 99 return 0; 100 } 101 ถ้าจะลองใช้คำสั่ง pthread_cond_broadcast() เพื่อส่งสัญญาณไปยังทุกเทรดที่มีหลายเทรด (ตามจำนวนที่กำหนด โดย NUM_THREADS) และรอตัวแปรเงื่อนไขเดียวกัน ก็มีตัวอย่างดังนี้ #include <stdio.h> 1 #include <stdlib.h> 2 #include <unistd.h> 3 #include <stdbool.h> 4 #include <time.h> 5 #include <pthread.h> 6 7 #define NUM_THREADS (4) 8 9 // global variables 10 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 11 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 12 static bool is_running = true; 13 14 void *thread_func( void *arg ) { 15 long id = (long)arg; 16 int ticks = 0; 17 while (is_running) { 18 pthread_mutex_lock( &mutex ); 19 pthread_cond_wait( &cond, &mutex ); 20 printf( "Thread: #%ld, ticks=%dn", id, ++ticks ); 21 pthread_mutex_unlock( &mutex ); 22 usleep(10); 23 } 24
14.
sleep(1); 25 printf( "nThread #%ld
exited..n", id ); 26 return NULL; 27 } 28 29 int main( int argc, char *argv[] ) { 30 int retval; 31 pthread_t threads[ NUM_THREADS ]; 32 33 srand( time(NULL) ); 34 35 // create a mutex lock 36 if ( pthread_mutex_init( &mutex, NULL ) ) { 37 printf( "Mutex init failed!n" ); 38 exit(1); 39 } 40 // create a condition variable 41 if ( pthread_cond_init( &cond, NULL ) ) { 42 printf( "Cond init failed!n" ); 43 exit(1); 44 } 45 // create threads 46 for ( int i=0; i < NUM_THREADS; i++ ) { 47 retval = pthread_create( 48 &threads[i], NULL, thread_func, 49 (void*) (long)(i+1) ); 50 if (retval) { 51 printf( "Create a new thread failed!.n" ); 52 exit(1); 53 } 54 } 55 56 usleep( 1000 ); 57 int N = 10; 58 for ( int i=0; i < N; i++ ) { 59 pthread_mutex_lock( &mutex ); 60 is_running = (i==N-1) ? false : true; 61 pthread_cond_broadcast( &cond ); 62 pthread_mutex_unlock( &mutex ); 63 printf("-------------------------n"); 64 usleep( (rand()%1000)*1000 ); 65 } 66 67 sleep(1); 68 for (int i=0; i < NUM_THREADS; i++) { 69 pthread_join( threads[i], NULL ); 70 } 71 pthread_cond_destroy( &cond ); // destroy condition variable 72 pthread_mutex_destroy( &mutex ); // destroy mutex lock 73 printf( "Done...nn" ); 74 return 0; 75 } 76 ตัวอย่างที่ 5: การใช้ Barrier ในกรณีที่มีการสร้างเทรดขึ้นมาทำงานไปพร้อม ๆ กัน แต่จะต้องมีการรอจังหวะให้ทุกเทรดทำงานในแต่ละขั้นตอนย่อย เสร็จครบทุกเทรด แล้วจึงอนุญาตให้ทุกเทรดสามาารถทำงานในขั้นตอนต่อไปได้เราจะใช้สิ่งที่เรียกว่า Barrier เปรียบ เสมือนแผงกั้นให้ทุกเทรดมาถึงจนครบตามจำนวนที่กำหนดไว้จึงเปิดขึ้นให้ทำงานต่อไปได้ การใช้POSIX Pthreads ก็มีชนิดของข้อมูล แต่คำสั่งที่เกี่ยวข้องดังนี้ pthread_barrier_init() สร้าง Barrier สำหรับใช้งาน pthread_barrier_wait() รอจนกว่าจะได้รับการแจ้งให้ผ่านไปได้ pthread_barrier_destroy() เลิกใช้Barrier
15.
ตัวอย่างโค้ดสาธิตการใช้Barrier มีดังนี้ โดยมีการสร้างเทรดขึ้นมาตามจำนวนที่กำหนด
(NUM_THREADS) และทุก เทรดที่สร้างขึ้นมานั้นรวมถึงเทรดหลักจะต้องรอจังหวะกันโดยใช้คำสั่ง pthread_barrier_wait() #include <stdio.h> 1 #include <stdlib.h> 2 #include <unistd.h> 3 #include <stdbool.h> 4 #include <time.h> 5 #include <pthread.h> 6 7 #define NUM_THREADS (4) 8 9 // global variables 10 static pthread_barrier_t barrier; 11 static bool is_running = true; 12 13 void *thread_func( void *arg ) { 14 long id = (long)arg; 15 int ticks = 0; 16 while (is_running) { 17 pthread_barrier_wait( &barrier ); 18 printf( "Thread: #%ld, ticks=%dn", id, ++ticks ); 19 usleep( (1+rand()%2000)*1000 ); 20 } 21 sleep(1); 22 printf( "nThread #%ld exited..n", id ); 23 return NULL; 24 } 25 26 int main( int argc, char *argv[] ) { 27 int retval; 28 pthread_t threads[ NUM_THREADS ]; 29 30 srand( time(NULL) ); 31 32 // create a barrier 33 if (pthread_barrier_init( &barrier, NULL, NUM_THREADS+1) ) { 34 printf( "Barrier init failed!n" ); 35 exit(1); 36 } 37 // create threads 38 for (int i=0; i < NUM_THREADS; i++ ) { 39 retval = pthread_create( 40 &threads[i], NULL, thread_func, 41 (void*) (long)(i+1) ); 42 if (retval) { 43 printf( "Create a new thread failed!n" ); 44 exit(1); 45 } 46 } 47 48 for ( int i=0; i < 10; i++ ) { 49 pthread_barrier_wait( &barrier ); 50 } 51 52 is_running = false; 53 for (int i=0; i < NUM_THREADS; i++) { 54 pthread_join( threads[i], NULL ); 55 } 56 pthread_barrier_destroy( &barrier ); // destroy barrier 57 printf( "Done...nn" ); 58 return 0; 59 } 60
16.
ตัวอย่างโค้ด C++ สาธิตการใช้งาน
std::thread ตัวอย่างที่ 1: Thread Creation โค้ดในตัวอย่างนี้สาธิตการสร้างเทรด (std::thread) จำนวน 2 เทรด (thread1 และ thread2) และเมื่อเทรดทำงาน จะ ต้องมีการล็อคการใช้งานของ Mutex (std::mutex) ให้ได้ก่อนแล้วจึงจะแสดงหมายเลขของเทรดเป็นข้อความ จากนั้น จะมีการรอเวลาซึ่งมีระยะเวลาตามตัวเลขสุ่มในช่วง 1000 ถึง 2000 (มิลลิวินาที) แล้วจึงปลดล็อค Mutex // g++ -std=c++14 main.cc -o main -lpthread 1 2 #include <iostream> // for std::cout 3 #include <thread> // for std:thread 4 #include <mutex> // for std::mutex 5 #include <cstdlib> // for std::srand(), std::rand() 6 #include <vector> // for std::vector() 7 8 using namespace std::chrono; 9 using namespace std::literals::chrono_literals; 10 11 // global variable 12 std::mutex output_lock; 13 14 static void thread_func( long arg ) { 15 output_lock.lock(); 16 std::cout << "Thread #" << arg << "n"; 17 // generate a random integer value between 1000..2000 18 long msec = 1000 + (std::rand() % 1000); 19 std::this_thread::sleep_for( 20 std::chrono::milliseconds(msec) ); 21 output_lock.unlock(); 22 } 23 24 int main() { 25 std::srand( std::time(nullptr) ); // set seed value 26 27 // create two threads 28 std::thread thread1( thread_func, 1 ); 29 std::thread thread2( thread_func, 2 ); 30 // sleep for 1 second 31 std::this_thread::sleep_for( 1s ); 32 // wait for threads 1 and 2 33 if( thread1.joinable() ) { 34 thread1.join(); 35 } 36 if( thread2.joinable() ) { 37 thread2.join(); 38 } 39 return 0; 40 } 41 ตัวอย่างที่ 2: Mutex การเขียนโค้ดภาษา C++ นั้น มีความหลากหลายมากกว่าภาษา C เนื่องจากรองรับการเขียนโปรแกรมแบบเชิงวัตถุ และมี การสร้างคลาส C++ ไว้สำหรับใช้งานได้เป็นมาตรฐาน ตัวอย่างโค้ดต่อไปนี้ ให้ผลการทำงานเหมือนโค้ดตัวอย่างแรก แต่มีการเพิ่มจำนวนเทรดให้มีมากกว่า 2 ได้และมีรูปแบบการเขียนที่แตกต่างกันออกไป เช่น มีการใช้เวกเตอร์ (std::vector) สำหรับอ้างอิงออปเจกต์ของเทรด (std::thread) ที่ได้มีการสร้างขึ้นมา และมีการสร้างฟังก์ชันสำหรับ เทรดแต่ละเทรด ให้อยู่ในรูปแบบที่เรียกว่า Anonymous Function // g++ -std=c++14 main.cc -o main -lpthread 1 2
17.
#include <iostream> //
for std::cout 3 #include <thread> // for std:thread 4 #include <mutex> // for std::mutex 5 #include <cstdlib> // for std::srand(), std::rand() 6 #include <vector> // for std::vector 7 #include <algorithm> // for std::for_each() 8 9 using namespace std::chrono; 10 using namespace std::literals::chrono_literals; 11 12 // global variable 13 std::mutex output_lock; 14 15 int main() { 16 std::srand( std::time(nullptr) ); 17 18 const int NUM_THREADS = 10; 19 // use a vector container stores threads 20 std::vector<std::thread> workers; // worker threads 21 for ( int i=0; i < NUM_THREADS; i++ ) { 22 // create a thread with an anonymous function 23 // and add it to the vector container 24 workers.push_back( std::thread ( [](long arg){ 25 output_lock.lock(); 26 std::cout << "Thread #" << arg << "n"; 27 // generate a random integer value between 1000..2000 28 long msec = 1000 + (std::rand() % 1000); 29 std::this_thread::sleep_for( 30 std::chrono::milliseconds(msec) ); 31 output_lock.unlock(); 32 }, i+1) ); 33 } 34 35 // sleep for 1 second 36 std::this_thread::sleep_for(1s); 37 38 // wait for worker threads 39 std::for_each(workers.begin(),workers.end(),[](std::thread& t) { 40 if (t.joinable()) { 41 t.join(); 42 } 43 }); 44 return 0; 45 } 46 47 ตัวอย่างที่ 3: Condition Variable โค้ดในตัวอย่างนี้สาธิตการใช้งาน Mutex (std::mutex) ร่วมกับตัวแปรเงื่อนไข (std::condition_variable) โดยให้ เทรดหลักของฟังก์ชัน main() คอยส่งสัญญาณโดยใช้คำสั่ง notify_onice(...) ไปยังอีกเทรดหนึ่งที่ถูกสร้างขึ้นใหม่ (เป็นการส่งสัญญาณรอจังหวะในทิศทางเดียว) และให้เทรดนั้นรอสัญญาณแบบไม่จำกัดเวลาโดยใช้คำสั่ง wait(...) สำหรับตัวแปรเงื่อนไข ในการทำงานแต่ละรอบของลูป while // g++ -std=c++14 main.cc -o main -lpthread 1 2 #include <iostream> // for std::cout 3 #include <thread> // for std:thread 4 #include <mutex> // for std::mutex 5 #include <condition_variable> // for std::condition_variable 6 7 using namespace std::chrono; 8 using namespace std::literals::chrono_literals; 9 10 // global variable 11 std::mutex mtx; 12 std::condition_variable cv; 13
18.
bool running =
true; 14 bool ready = false; 15 16 void thread_func() { 17 int ticks = 0; 18 while (running) { 19 std::unique_lock<std::mutex> lock(mtx); 20 while (!ready) { 21 cv.wait( lock ); 22 } 23 ready = false; 24 if (running) { 25 std::cout << "Thread: ticks=" << (++ticks) << "n"; 26 } 27 // The mutex lock is automatically released after each while loop. 28 } 29 } 30 31 int main() { 32 // create a thread 33 std::thread t( thread_func ); 34 35 for ( int i=0; i < 10; i++ ) { 36 mtx.lock(); 37 ready = true; 38 cv.notify_one(); 39 mtx.unlock(); 40 std::this_thread::sleep_for(500ms); 41 } 42 43 mtx.lock(); 44 ready = true; 45 running = false; 46 cv.notify_one(); 47 mtx.unlock(); 48 if ( t.joinable() ) { 49 t.join(); 50 } 51 return 0; 52 } 53 ถ้าจะเปลี่ยนมาใช้คำสั่ง wait_for(...) ซึ่งเป็นการรอที่มีระยะเวลาจำกัด (Timeout) สำหรับตัวแปรเงื่อนไข ก็มีตัวอย่าง โค้ดดังนี้ // g++ -std=c++14 main.cc -o main -lpthread 1 2 #include <iostream> // for std::cout 3 #include <thread> // for std:thread 4 #include <mutex> // for std::mutex 5 #include <condition_variable> // for std::condition_variable 6 7 using namespace std::chrono; 8 using namespace std::literals::chrono_literals; 9 10 // global variable 11 std::mutex mtx; 12 std::condition_variable cv; 13 bool running = true; 14 bool ready = false; 15 16 void thread_func() { 17 int ticks = 0; 18 while (running) { 19 std::unique_lock<std::mutex> lock(mtx); 20 if ( cv.wait_for(lock,milliseconds(10))!=std::cv_status::timeout ){ 21 if (ready) { 22 std::cout << "Thread: ticks=" << (++ticks) << "n"; 23 ready = false; 24
19.
} 25 } 26 // The mutex
lock is automatically released after each while loop. 27 } 28 } 29 30 int main() { 31 // create a thread 32 std::thread t( thread_func ); 33 34 for ( int i=0; i < 10; i++ ) { 35 mtx.lock(); 36 ready = true; 37 cv.notify_one(); 38 mtx.unlock(); 39 std::this_thread::sleep_for(500ms); 40 } 41 42 mtx.lock(); 43 ready = true; 44 running = false; 45 cv.notify_one(); 46 mtx.unlock(); 47 if ( t.joinable() ) { 48 t.join(); 49 } 50 return 0; 51 } 52 ปรับปรุงแก้ไขล่าสุด: 2021-08-29