POSIX Thread Anatomy
Last updated
Last updated
Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University
ภายในระบบปฏิบัติการลีนุกซ์นั้นจะรองรับการทำงานแบบหลายงานพร้อมกัน (multitasking support) โดยตัวโปร-เซสเองจะสามารถสร้างงานย่อยๆได้เรียกส่วนนี้ว่า เทรด (thread) หรืออีกชื่อหนึ่งว่า “lightweight processes” ข้อดีของการใช้ thread คือจะสามารถทำให้นักพัฒนาโปรแกรมทำการจัดการกับเหตุการณ์ที่เกิดขึ้นในเวลาที่ไม่แน่นอน (asynchronous events) ได้อย่างทันทีและมีประสิทธิภาพ นอกจากนั้นสามารถใช้ในการประมวลในลักษณะขนาน (parallel computing) บนเครื่องที่มีหน่วยประมวลผลแบบหลายหน่วยประมวลผล (multi-core CPU) ที่ใช้หน่วยความจำร่วมกันได้ดี (shared-memory multiprocessor)
โดยทั่วไปแล้วโปรเซสภายในระบบปฏิบัติการลีนุกซ์จะประกอบด้วยสถานะของหน่วยประมวลผล (เช่นค่าภายในตัวรีจิสเตอร์ AX,BX,DX
) รายละเอียดของการจองหน่วยความจำ (สำหรับเก็บ code, globals, heap และ stack) และรายละเอียดที่เกี่ยวข้องกับระบบปฏิบัติการ (เช่น การเปิดไฟล์, หมายเลขโปรเซส) ซึ่งเทรดก็จะคล้ายกัน แต่จะต่างกันตรงที่โปรเซสแต่ละตัวจะแยกการเก็บสถานะกันอย่างชัดเจน ในขณะที่แต่ละเทรดจะมีการใช้ code, globals และ heap ร่วมกัน
ซึ่งเทรดจะสามารถทำงานได้ดีในกรณีที่เครื่องคอมพิวเตอร์นั้นมีมากกว่าหนึ่งหน่วยประมวลผล โดยในรูปข้างล่างแสดงการทำงานของเทรดแต่ละตัว (ได้แก่ main(), function1()
และ function2()
) ซึ่งถ้าเครื่องมีหน่วยประมวลผลเพียงตัวเดียวการทำงานของโปรแกรมนี้ก็จะทำตามลำดับของคำสั่งแต่ละบรรทัด (program counter) ซึ่งอาจจะใช้เวลาทั้งสิ้น 2 นาที แต่ถ้าเครื่องมีหน่วยประมวลผลจำนวน 3 ตัวทั้งสามส่วนก็จะแยกกันทำงานไปแต่ละหน่วยประมวลผลซึ่งอาจจะใช้เวลาทั้งสิ้นเพียง 50 วินาทีเท่านั้น
ตัวเทรดแต่ละตัวภายในโปรเซสจะใช้ทรัพยาการเดียวกับโปรเซส แต่อย่างไรก็ตามระบบปฏิบัติการก็สามารถจัดตารางให้การทำงานของแต่ thread ได้อย่างอิสระ เนื่องจากพวกมันเพียงแค่คัดลอกเอาทรัพยากรไปเพียงเล็กน้อยเท่านั้นเพื่อแยกไปเป็นโปรแกรมเล็กอีกตัวดังแสดงในรูปข้างบน
การสื่อสารกันระหว่างเทรดจะสามารถติดต่อผ่านกันได้ทางหน่วยความจำที่ใช้งานร่วมกันอยู่ได้ทันที
ในขณะที่
การสื่อสารระหว่างโปรเซสจะสามารถติดต่อผ่านกันได้ต้องผ่านทางระบบปฏิบัติการเท่านั้น เช่นผ่านไฟล์, ผ่าน pipe
หรือผ่าน socket
เป็นต้น
ไลบรารี POSIX thread ถือว่าเป็นตัวมาตราฐานหลักในการเขียนเทรดสำหรับโปรแกรมภาษา C/C++ ซึ่งเป็นไลบรารีที่จัดเตรียมฟังก์ชันต่างๆเกี่ยวกับการจัดการเทรดและจะทำงานได้มีประสิทธิภาพมากสำหรับระบบคอมพิวเตอร์ที่มีหลายหน่วยประมวลผลกลาง (multi-processor หรือ multi-core systems) เนื่องจากมีฟังก์ชันในการจัดตารางการทำงานของโปรเซสบนแต่ละหน่วยประมวลผลกลางที่อยู่ภายในระบบคอมพิวเตอร์ตัวเดียวกันและเทรดทุกตัวที่อยู่ภายในโปรเซสเดียวกันนั้นก็จะใช้พื้นที่ในหน่วยความจำเดียวกัน (address space) ซึ่งแตกต่างจากเทคโนโลยีในการเขียนโปรแกรมแบบขนาน (Parallel programming) เช่น MPI และ PVM ที่ถูกใช้ในสภาพแวดล้อมการคำนวณแบบกระจาย (distributed computing) ไปยังระบบคอมพิวเตอร์เครื่องอื่นๆ ที่อยู่ไกลออกไปหรือต่างสถานที่กัน
ฟังก์ชันและตัวแปรที่เกี่ยวข้อง
ไลบรารีที่เกี่ยวข้องคือ pthread.h
ฟังก์ชัน int pthread_create(pthread_t *new_thread_ID, const pthread_attr_t *attr, void * (*start_func)(void *), void *arg);
สำหรับสร้าง thread ตัวใหม่ (new_thread_ID
) และกำหนดฟังก์ชัน (*start_func
) ที่จะให้ทำงานเมื่อ thread ถูกเรียกขึ้นมา โดยสามารถระบุพารามิเตอร์ที่จะส่งไปยังฟังก์ชันของ thread ได้ (arg
)
ฟังก์ชัน int pthread_join(pthread_t target_thread, void **status);
สำหรับเรียกให้ thread นั้น (target_thread
) ทำงานขึ้นมา
ฟังก์ชัน void pthread_exit(void *retval);
สำหรับสั่งให้ thread สิ้นสุดการทำงาน
ขบวนการทำงานของเทรดนั้นจะประกอบไปด้วย สร้างเทรด (thread creation), สิ้นสุดการทำงาน (termination), ทำงานตามจังหวะ (thread synchronization ด้วยวิธีการแบบ joins, blocking เป็นต้น), การจัดลำดับการทำงาน (scheduling), การจัดการข้อมูล (data management) และ การติดต่อกันระหว่างกัน (process interaction)
พื้นที่ที่ใช้งานร่วมกันของเทรดทั้งหมดภายในโปรเซสประกอบไปด้วย
ชุดคำสั่งโปรเซส (Process instructions)
ค่า files descriptors ที่มีการเปิดไว้
สัญญาณ (signals) และตัวดำเนินการ (signal handlers)
ไดเรดทอรี่ปัจจุบัน (current working directory)
หมายเลข User และ Group
โดยแต่ละเทรดจะมี:
หมายเลขเทรด (Thread ID)
กลุ่มตัวแปรรีจิสเตอร์ (set of registers) และ stack pointer
สแต็คสำหรับเก็บค่าตัวแปร (local variables)
signal mask
ค่า priority
ค่าสถานะที่ส่งกลับ: errno
และเมื่อต้องการคอมไพล์โปรแกรมจะต้องมีการอ้างอิงไลบรารี Posix threads ด้วย -lpthread
ดังตัวอย่าง
เมื่อเปรียบเทียบการสร้างและจัดการโปรเซสแล้ว การใช้ thread จะมีการใช้ทรัพยากรของระบบน้อยกว่ามาก และเกิด overhead กับระบบปฏิบัติการที่น้อยกว่าอย่างเห็นได้ชัด จากตัวอย่างโปรแกรมข้างล่างจะแสดงระยะเวลาของการสร้างโปรเซสและ thread ด้วยจำนวน 50,000 ตัว ภายใต้สภาพแวดล้อมเดียวกัน โดยจะมีการนับหน่วยเวลาทั้งสามแบบคือ real time, user time และ system time
ตาราง 5-3 แสดงผลการทดสอบบนหน่วยประมวลผลรุ่นต่างๆ
Ref: https://computing.llnl.gov/tutorials/pthreads/