สัญญาณคืออะไร?


351

สัญญาณเป็นแนวคิดการเขียนโปรแกรมที่ใช้บ่อยในการแก้ปัญหาหลายเธรด คำถามของฉันถึงชุมชน:

เซมาฟอร์คืออะไรและคุณใช้มันอย่างไร


14
แฟล็กบูลีนที่มีค่าขึ้นอยู่กับว่าตัวนับจำนวนเต็มถึงขีด จำกัด สูงสุดที่กำหนดหรือไม่ ทำให้งงงวยสูงสุด!
แซม

คำตอบ:


400

คิดว่า semaphores เป็นกระเด้งที่ไนต์คลับ มีผู้คนจำนวนมากที่ได้รับอนุญาตในสโมสรพร้อมกัน หากสโมสรเต็มไม่มีใครได้รับอนุญาตให้เข้า แต่ทันทีที่คนคนหนึ่งออกจากบุคคลอื่นอาจเข้า

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

นี่คือตัวอย่างที่สอนมากใน C # :-)

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TheNightclub
{
    public class Program
    {
        public static Semaphore Bouncer { get; set; }

        public static void Main(string[] args)
        {
            // Create the semaphore with 3 slots, where 3 are available.
            Bouncer = new Semaphore(3, 3);

            // Open the nightclub.
            OpenNightclub();
        }

        public static void OpenNightclub()
        {
            for (int i = 1; i <= 50; i++)
            {
                // Let each guest enter on an own thread.
                Thread thread = new Thread(new ParameterizedThreadStart(Guest));
                thread.Start(i);
            }
        }

        public static void Guest(object args)
        {
            // Wait to enter the nightclub (a semaphore to be released).
            Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
            Bouncer.WaitOne();          

            // Do some dancing.
            Console.WriteLine("Guest {0} is doing some dancing.", args);
            Thread.Sleep(500);

            // Let one guest out (release one semaphore).
            Console.WriteLine("Guest {0} is leaving the nightclub.", args);
            Bouncer.Release(1);
        }
    }
}

6
ถ้าเป็นเหมือนกระเด้งที่ไนท์คลับควรปล่อยให้ผู้เข้าพักเรียงตามลำดับ แต่เมื่อฉันลองมันก็เป็นการสุ่ม เช่น. แขก 40 มาก่อนก่อนแขก 39 มีอะไรบ้างที่เราสามารถทำได้เพื่อควบคุมสิ่งนี้
ใช้การ

2
@TNA: ใช่ว่าเกี่ยวข้องกับวิธีการเริ่มเธรดใหม่ในตัวอย่างนี้และไม่ได้อยู่ในขอบเขตของคำตอบ
Patrik Svensson

5
การเปรียบเทียบของ Bouncer นั้นเป็นมหากาพย์แน่นอน แต่น่าสนใจที่มีการใช้งานแล้ว: albahari.com/threading/part2.aspx#_Semaphore
Igor Brejc

semaphores มีคุณค่าอย่างไรในระบบแบบกระจาย?
csandreas1

198

บทความMutexes และ Semaphores Demystifiedโดย Michael Barr เป็นการแนะนำสั้น ๆ เกี่ยวกับสิ่งที่ทำให้ mutexes และ semaphores แตกต่างกันและเมื่อควรและไม่ควรใช้ ฉันคัดลอกข้อความสำคัญหลายย่อหน้าที่นี่

จุดสำคัญคือควรใช้ mutexes เพื่อปกป้องทรัพยากรที่ใช้ร่วมกันในขณะที่ควรใช้ semaphores สำหรับการส่งสัญญาณ โดยทั่วไปคุณไม่ควรใช้เซมาฟอร์เพื่อปกป้องทรัพยากรที่ใช้ร่วมกันหรือ mutexes สำหรับการส่งสัญญาณ ยกตัวอย่างเช่นมีปัญหาเรื่องการเปรียบเทียบกับคนโกหกในแง่ของการใช้เซมาฟอร์เพื่อปกป้องทรัพยากรที่ใช้ร่วมกัน - คุณสามารถใช้วิธีนั้นได้ แต่มันอาจทำให้ยากที่จะวินิจฉัยข้อบกพร่อง

ในขณะที่ mutexes และ semaphores มีความคล้ายคลึงกันในการใช้งานของพวกเขาพวกเขาควรจะใช้ที่แตกต่างกันเสมอ

คำตอบที่พบบ่อยที่สุด (แต่ไม่ถูกต้องอย่างไรก็ตาม) สำหรับคำถามที่ถูกวางไว้ที่ด้านบนคือ mutexes และ semaphores มีความคล้ายคลึงกันมากโดยมีความแตกต่างอย่างมีนัยสำคัญเพียงอย่างเดียวว่า semaphores สามารถนับได้มากกว่าหนึ่ง วิศวกรเกือบทุกคนดูเหมือนจะเข้าใจอย่างถูกต้องว่า Mutex เป็นแฟล็กไบนารีที่ใช้เพื่อปกป้องทรัพยากรที่ใช้ร่วมกัน แต่เมื่อถูกถามให้ขยายวิธีการใช้ "การนับเซมาฟอร์นับ" วิศวกรส่วนใหญ่ - แตกต่างกันเพียงในระดับความเชื่อมั่นของพวกเขา - แสดงรสชาติของความคิดเห็นในตำราเรียนว่าสิ่งเหล่านี้ถูกใช้เพื่อปกป้องทรัพยากรที่เทียบเท่ากัน

...

ณ จุดนี้มีการเปรียบเทียบที่น่าสนใจโดยใช้ความคิดของกุญแจห้องน้ำเพื่อปกป้องทรัพยากรที่ใช้ร่วมกัน - ห้องน้ำ หากร้านค้ามีห้องน้ำเดียวกุญแจเดียวก็เพียงพอที่จะปกป้องทรัพยากรนั้นและป้องกันไม่ให้มีผู้ใช้หลายคนพร้อมกัน

หากมีห้องน้ำหลายห้องอาจถูกชักจูงให้คีย์พวกมันเหมือนกันและสร้างกุญแจหลายอัน - ซึ่งคล้ายกับสัญญาณที่ใช้ผิด เมื่อคุณมีรหัสคุณไม่ทราบว่าห้องน้ำมีให้บริการแบบใดและถ้าคุณลงเส้นทางนี้คุณอาจต้องใช้ mutexes เพื่อให้ข้อมูลนั้นและทำให้แน่ใจว่าคุณไม่ได้ใช้ห้องน้ำที่มีอยู่แล้ว .

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

...

การใช้สัญญาณที่ถูกต้องสำหรับการส่งสัญญาณจากงานหนึ่งไปยังงานอื่น mutex หมายถึงการใช้และปล่อยออกมาตามลำดับโดยแต่ละงานที่ใช้ทรัพยากรที่ใช้ร่วมกันซึ่งปกป้อง ในทางตรงกันข้ามงานที่ใช้เซมาฟอร์เป็นสัญญาณหรือรอ - ไม่ใช่ทั้งสองอย่าง ตัวอย่างเช่นภารกิจที่ 1 อาจมีรหัสที่จะโพสต์ (เช่นสัญญาณหรือการเพิ่มขึ้น) สัญญาณพิเศษเมื่อกดปุ่ม "พลังงาน" และงานที่ 2 ซึ่งทำให้การแสดงผลตื่นขึ้นมาใช้สัญญาณเดียวกัน ในสถานการณ์นี้งานหนึ่งคือผู้สร้างสัญญาณเหตุการณ์ อื่น ๆ ของผู้บริโภค

...

ที่นี่มีจุดสำคัญที่ทำให้ mutex เข้าไปยุ่งกับระบบปฏิบัติการแบบเรียลไทม์ในทางที่ไม่ดีทำให้เกิดการสลับลำดับความสำคัญซึ่งอาจมีการดำเนินการภารกิจที่มีความสำคัญน้อยกว่าก่อนงานสำคัญกว่าเนื่องจากการแบ่งปันทรัพยากร กล่าวโดยย่อนี้เกิดขึ้นเมื่องานที่มีลำดับความสำคัญต่ำกว่าใช้ mutex เพื่อคว้าทรัพยากร A จากนั้นพยายามที่จะคว้า B แต่หยุดชั่วคราวเนื่องจาก B ไม่พร้อมใช้งาน ในขณะที่กำลังรองานลำดับความสำคัญที่สูงขึ้นจะมาพร้อมกับความต้องการ A แต่มันถูกผูกไว้แล้วและโดยกระบวนการที่ไม่ได้ทำงานเพราะรอ B มีหลายวิธีในการแก้ไขปัญหานี้ แต่ส่วนใหญ่มักจะได้รับการแก้ไข โดยการแก้ไข mutex และตัวจัดการงาน Mutex ซับซ้อนกว่าในกรณีเหล่านี้มากกว่าเซมาฟอร์ไบนารี

...

สาเหตุของความสับสนในปัจจุบันที่แพร่หลายอย่างกว้างขวางระหว่าง mutexes และ semaphores นั้นเป็นเรื่องทางประวัติศาสตร์เนื่องจากมันย้อนกลับไปถึงปี 1974 การประดิษฐ์สัญญาณ (สัญลักษณ์ "S" ในบทความนี้) โดย Djikstra ก่อนหน้าวันที่นั้นไม่มีการประสานงานที่ปลอดภัยระหว่างเครื่องและกลไกการส่งสัญญาณที่นักวิทยาศาสตร์คอมพิวเตอร์รู้จักนั้นสามารถปรับขนาดได้อย่างมีประสิทธิภาพสำหรับการใช้งานมากกว่าสองงาน สัญญาณเซมาฟอร์ที่ปลอดภัยและปรับขนาดได้ของ Dijkstra ถูกนำไปใช้ในการป้องกันส่วนที่สำคัญและการส่งสัญญาณ และทำให้เกิดความสับสน

อย่างไรก็ตามต่อมาก็เห็นได้ชัดว่าผู้พัฒนาระบบปฏิบัติการหลังจากการปรากฏตัวของ RTOS ที่ยึดตามลำดับความสำคัญ (เช่น VRTX, แคลิฟอร์เนียปี 1980) การตีพิมพ์บทความทางวิชาการที่สร้าง RMA และปัญหาที่เกิดจากการกลับลำดับความสำคัญและกระดาษที่มีลำดับความสำคัญ โปรโตคอลการสืบทอดในปี 1990, [3] เห็นได้ชัดว่า mutexes จะต้องเป็นมากกว่า semaphores ที่มีตัวนับไบนารี

Mutex: การแบ่งปันทรัพยากร

สัญญาณ: สัญญาณ

อย่าใช้อย่างใดอย่างหนึ่งโดยไม่คำนึงถึงผลข้างเคียง


10
ดูเอกสาร PDF นี้พร้อมกันของ Stanford ดูหน้า 8 คำอธิบายข้างต้นจะเหมาะสมกว่า .. see.stanford.edu/materials/icsppcs107/ ......
Kris Subramanian

3
หนังสือเล่มเล็ก ๆ ของ semaphoresเป็นอ่านที่มีคุณค่าเกี่ยวกับปัญหาเหล่านี้
G. Bach

@KrisSubramanian ขอบคุณสำหรับลิงค์ แต่เอกสารกล่าวถึง semaphores และไม่มีอะไรใน Mutexes อย่างไรก็ตามคุณหมายถึงบัฟเฟอร์ที่ใช้ร่วมกันในตัวอย่างที่สามารถป้องกันได้โดยใช้ Mutex หรือไม่ แทนการมี 2 semaphores emptyBuffers และ fullBuffers
talekeDskobeDa

1
@Pramod True ลิงก์ไม่ได้เพิ่มบันทึกที่เกี่ยวข้องกับ Mutex ใด ๆ ฉันเพิ่มลิงค์เพื่อให้สัญญาณของสิ่งต่าง ๆ ชัดเจนสำหรับผู้อ่าน SO :) น่าสนใจในกรณีนี้บัฟเฟอร์ถูกใช้โดยไม่มีการล็อกใด ๆ เนื่องจากมันถูกเข้าถึงตามลำดับและในรูปแบบวงกลม ie Writer จะเขียนถึง 0 และส่งสัญญาณให้ผู้อ่านอ่านจาก 0 หากผู้อ่านไม่ได้อ่านจาก 0 และส่งสัญญาณให้นักเขียนนักเขียนจะบล็อก ดังนั้นไม่จำเป็นต้องใช้ mutex เพื่อล็อครีซอร์สทั่วไป นี่คือความแตกต่างจากการเปรียบเทียบห้องน้ำที่ได้รับข้างต้น
Kris Subramanian

@Kris Subramanian: เอกสารดี แต่มีความเข้าใจผิดเล็กน้อย: หน้า 3 เริ่มระบุว่า "แต่ละกระทู้ที่ล็อคสัญญาณควรจะระมัดระวังในการปลดล็อค" - พวกเขาสามารถปลดล็อคโดยกระทู้ใด ๆ หากคุณทำในเธรดเดียวกันคุณเพียงแค่ใช้มันเป็น "brocken mutex" "Brocken" เพราะยังสามารถปลดล็อกจากเธรดอื่นได้โดยไม่ตั้งใจ - เกิดข้อผิดพลาด - และทำลายตรรกะของคุณ ยังคงเอกสารที่ดีคิดว่า
Rustam A.

70

Mutex: การเข้าถึงทรัพยากรของสมาชิกพิเศษ

สัญญาณ: n- สมาชิกเข้าถึงทรัพยากร

นั่นคือ mutex สามารถใช้เพื่อซิงโครไนซ์การเข้าถึงตัวนับไฟล์ฐานข้อมูลและอื่น ๆ

sempahore สามารถทำสิ่งเดียวกัน แต่รองรับจำนวนผู้โทรพร้อมกันคงที่ ตัวอย่างเช่นฉันสามารถตัดการเรียกฐานข้อมูลในเซมาฟอร์ (3) เพื่อให้แอพแบบมัลติเธรดของฉันจะเข้าสู่ฐานข้อมูลด้วยการเชื่อมต่อพร้อมกันสูงสุด 3 รายการ ความพยายามทั้งหมดจะปิดกั้นจนกว่าหนึ่งในสามช่องจะเปิดขึ้น พวกเขาทำสิ่งต่าง ๆ เช่นการควบคุมปริมาณที่ไร้เดียงสาง่ายมาก


20
ตามที่ Richard W. Stevens กล่าวว่าจริง ๆ แล้ว mutex นั้นเป็นสัญญาณแบบไบนารีด้วยค่าที่เป็นไปได้สองค่าเท่านั้น: 0 และ 1
Qiang Xu

19
@QiangXu ในระบบปฏิบัติการ Internals และหลักการออกแบบโดย William Stallings สัญญาณแบบไบนารีนั้นแตกต่างจาก mutex ในวิธีที่สำคัญอย่างหนึ่งและฉันเสนอราคา: "ความแตกต่างที่สำคัญระหว่าง mutex และสัญญาณแบบไบนารีคือกระบวนการที่ล็อค mutex จะต้องเป็นหนึ่งในการปลดล็อคในทางตรงกันข้ามมันเป็นไปได้สำหรับกระบวนการหนึ่งที่จะล็อคสัญญาณสัญญาณแบบไบนารีและอีกวิธีหนึ่งในการปลดล็อค " .
กาแฟไฟฟ้า

3
มีความเสี่ยงที่จะแสดงความคิดเห็นในเธรดเก่าสิ่งนี้ไม่ถูกต้อง ตามที่ @AdamDavis ได้กล่าวมาแล้วเซมาฟอร์ไม่ควรใช้ (ต้อง?) สำหรับการเข้าถึงทรัพยากรของสมาชิก n ซึ่งยังควรทำโดยใช้ Mutex พิจารณาความคล้ายคลึงของห้องน้ำใน Coffeeshop กับคนหลายคนที่รอการเข้าถึงหรืออย่างอื่นหลายห้องน้ำที่มีกุญแจคล้ายกับห้องน้ำ สัญญาณควรใช้สัญญาณระหว่างงาน
cspider

21

ลองพิจารณารถแท็กซี่ที่สามารถรองรับได้ทั้งหมด 3 ( ด้านหลัง ) +2 ( ด้านหน้า ) รวมถึงคนขับ ดังนั้นsemaphoreอนุญาตให้มีเพียง 5 คนเท่านั้นในเวลาเดียวกัน และmutexอนุญาตให้เพียง 1 คนในที่นั่งเดียวของรถ

ดังนั้นMutexเพื่อให้การเข้าถึงเฉพาะสำหรับทรัพยากร ( เช่นด้าย OS ) ในขณะที่Semaphoreเพื่อให้การเข้าถึงสำหรับnจำนวนของทรัพยากรในเวลา


19

@Craig:

สัญญาณส่งสัญญาณเป็นวิธีการล็อคทรัพยากรเพื่อให้มั่นใจได้ว่าในขณะที่ดำเนินการรหัสชิ้นส่วนรหัสเท่านั้นที่มีการเข้าถึงทรัพยากรที่ สิ่งนี้ทำให้เธรดสองเธรดไม่พร้อมใช้งานทรัพยากรซึ่งอาจทำให้เกิดปัญหาได้

สิ่งนี้ไม่ จำกัด เพียงหนึ่งเธรด เซมาฟอร์สามารถกำหนดค่าเพื่ออนุญาตให้เธรดจำนวนคงที่สามารถเข้าถึงทรัพยากรได้


7
นี่เป็นคำอธิบายไม่ใช่คำตอบ
kaspersky

11
ใช่ แต่ฉันคิดว่าฉันเขียนสิ่งนี้ก่อนที่ความคิดเห็นจะถูกเพิ่มไปยัง Stack Overflow หรือฉันไม่จำไม่ได้จริงๆ เวลานี้ฉันตอบในความคิดเห็นว่า :-)
Mats Fredriksson

16

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

สัญญาณที่นี่ไม่ได้ใช้เป็นกลไกการยกเว้น แต่เป็นกลไกการส่งสัญญาณ งานที่ใช้กำลังรอเซมาฟอร์งานที่สร้างกำลังโพสต์เซมาฟอร์

วิธีนี้ภารกิจการบริโภคจะรันเมื่อและต่อเมื่อมีข้อมูลที่จะถูก dequeued


11

มีสองแนวคิดที่สำคัญในการสร้างโปรแกรมที่เกิดขึ้นพร้อมกัน - การประสานและการยกเว้นซึ่งกันและกัน เราจะเห็นว่าการล็อคสองประเภทนี้ (เซมาฟอร์เป็นกลไกการล็อคประเภทใด) ช่วยให้เราสามารถทำการซิงโครไนซ์และการแยกออกจากกันได้

สัญญาณเป็นโครงสร้างการเขียนโปรแกรมที่ช่วยให้เราบรรลุการทำงานพร้อมกันโดยการใช้การประสานและการยกเว้นซึ่งกันและกัน Semaphores มีสองประเภทคือไบนารีและการนับ

สัญญาณมีสองส่วนคือตัวนับและรายการของงานที่รอการเข้าถึงทรัพยากรที่เฉพาะเจาะจง สัญญาณดำเนินการสองการดำเนินการ: รอ (P) [นี้เป็นเหมือนการได้รับล็อค] และปล่อย (V) [คล้ายกับการปล่อยล็อค] - เหล่านี้เป็นเพียงสองการดำเนินงานที่สามารถดำเนินการในสัญญาณ ในเซมาฟอร์ไบนารีตัวนับเชิงตรรกะจะอยู่ระหว่าง 0 ถึง 1 คุณสามารถคิดว่ามันคล้ายกับล็อคที่มีค่าสองค่า: เปิด / ปิด สัญญาณการนับมีหลายค่าสำหรับการนับ

สิ่งสำคัญคือต้องเข้าใจว่าตัวนับสัญญาณส่งสัญญาณติดตามจำนวนงานที่ไม่ต้องปิดกั้นคือสามารถดำเนินการต่อได้ งานบล็อกและเพิ่มตัวเองลงในรายการเซมาฟอร์ก็ต่อเมื่อตัวนับเป็นศูนย์ ดังนั้นงานจะถูกเพิ่มไปยังรายการในรูทีน P () หากไม่สามารถดำเนินการได้และ "ทำให้" ใช้รูทีน V ()

ตอนนี้มันค่อนข้างชัดเจนว่าจะเห็นว่า semaphores ไบนารีสามารถใช้ในการแก้ปัญหาการซิงโครไนซ์และการแยกซึ่งกันและกัน - พวกมันถูกล็อคเป็นหลัก

อดีต การประสานข้อมูล:

thread A{
semaphore &s; //locks/semaphores are passed by reference! think about why this is so.
A(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
;// some block of code B2
...
}

//thread B{
semaphore &s;
B(semaphore &s): s(s){} //constructor
foo(){
...
...
// some block of code B1
s.V();
..
}

main(){
semaphore s(0); // we start the semaphore at 0 (closed)
A a(s);
B b(s);
}

ในตัวอย่างข้างต้น B2 สามารถดำเนินการได้หลังจาก B1 เสร็จสิ้นการดำเนินการแล้วเท่านั้น สมมติว่าเธรด A เข้าสู่การประมวลผลก่อน - ไปที่ sem.P () และรอเนื่องจากตัวนับเป็น 0 (ปิด) เธรด B จะมาพร้อมกันเสร็จสิ้น B1 แล้วปลดปล่อยเธรด A ซึ่งจะทำให้ B2 เสร็จสมบูรณ์ ดังนั้นเราจึงบรรลุการประสาน

ตอนนี้เรามาดูการแยกซึ่งกันและกันด้วยสัญญาณแบบไบนารี:

thread mutual_ex{
semaphore &s;
mutual_ex(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
//critical section
s.V();
...
...
s.P();
//critical section
s.V();
...

}

main(){
semaphore s(1);
mutual_ex m1(s);
mutual_ex m2(s);
}

การยกเว้นซึ่งกันและกันนั้นค่อนข้างง่ายเช่นกัน - m1 และ m2 ไม่สามารถเข้าสู่ส่วนวิกฤติในเวลาเดียวกันได้ ดังนั้นแต่ละเธรดใช้เซมาฟอร์เดียวกันเพื่อให้การยกเว้นซึ่งกันและกันสำหรับสองส่วนที่สำคัญ ตอนนี้เป็นไปได้ไหมที่จะมีภาวะพร้อมกันมากขึ้น? ขึ้นอยู่กับส่วนที่สำคัญ (ลองคิดดูว่ามีวิธีอื่นที่สามารถใช้เซมาฟอร์เพื่อให้เกิดการแยกกัน .. คำใบ้: ฉันจำเป็นต้องใช้เซมาฟอร์เดียวหรือไม่?)

การนับสัญญาณ: สัญญาณที่มีมากกว่าหนึ่งค่า ลองดูว่านี่หมายถึงอะไร - ล็อคที่มีค่ามากกว่าหนึ่งค่า? เปิดปิดและ ... อืม การใช้งานแบบหลายขั้นตอนในการแยกหรือการซิงโครไนซ์ร่วมกันคืออะไร

มาง่ายกว่ากันสอง:

การซิงโครไนซ์โดยใช้เซมาฟอร์นับ: สมมติว่าคุณมี 3 งาน - # 1 และ 2 ที่คุณต้องการดำเนินการหลังจาก 3. คุณจะออกแบบการซิงโครไนซ์ของคุณอย่างไร?

thread t1{
...
s.P();
//block of code B1

thread t2{
...
s.P();
//block of code B2

thread t3{
...
//block of code B3
s.V();
s.V();
}

ดังนั้นถ้าเซมาฟอร์ของคุณเริ่มปิดคุณต้องแน่ใจว่าบล็อก t1 และ t2 ได้รับการเพิ่มในรายการเซมาฟอร์ จากนั้นมาพร้อมกับ t3 ที่สำคัญทั้งหมดเสร็จสิ้นธุรกิจและปลดปล่อย t1 และ t2 สิ่งที่พวกเขาเป็นอิสระในการสั่งซื้อ? ขึ้นอยู่กับการใช้งานรายการเซมาฟอร์ อาจเป็น FIFO อาจขึ้นอยู่กับลำดับความสำคัญบางอย่าง ฯลฯ (หมายเหตุ: คิดว่าคุณจะจัดการ P และ V ของคุณอย่างไรถ้าคุณต้องการให้ t1 และ t2 ดำเนินการตามลำดับเฉพาะและถ้าคุณไม่ทราบถึงการนำเซมาฟอร์มาใช้)

(หาคำตอบ: จะเกิดอะไรขึ้นถ้าจำนวนของ V มากกว่าจำนวน P?)

การยกเว้นร่วมกันโดยใช้การนับเซมาฟอร์: ฉันต้องการให้คุณสร้างรหัสเทียมของคุณเองสำหรับสิ่งนี้ (ทำให้คุณเข้าใจในสิ่งที่ดีกว่า!) - แต่แนวคิดพื้นฐานคือ: เซมาฟอร์นับของเคาน์เตอร์ = N ช่วยให้งานเข้าสู่ส่วนวิกฤติได้อย่างอิสระ . สิ่งนี้หมายความว่าคุณมีงาน N (หรือกระทู้ถ้าคุณต้องการ) เข้าสู่ส่วนที่สำคัญ แต่งาน N + 1th ถูกบล็อก (ไปที่รายการงานที่ถูกบล็อกที่เราโปรดปราน) และจะปล่อยให้ผ่านเมื่อใครบางคน V สัญญาณ อย่างน้อยหนึ่งครั้ง ดังนั้นเซมาฟอร์นับ, แทนที่จะแกว่งระหว่าง 0 และ 1, ตอนนี้ไประหว่าง 0 และ N, อนุญาตให้งาน N เข้าและออกได้อย่างอิสระ, ปิดกั้นไม่มีใคร!

เอ้ยทำไมคุณต้องเป็นคนงี่เง่า? จุดรวมของการแยกซึ่งกันและกันไม่ใช่การปล่อยให้คนมากกว่าหนึ่งคนเข้าถึงทรัพยากรหรือไม่? (เคล็ดลับคำแนะนำ ... คุณไม่ได้มีเพียงหนึ่งไดรฟ์ในคอมพิวเตอร์ของคุณใช่ไหม ... ?)

ที่จะคิดเกี่ยวกับ : การแยกซึ่งกันและกันทำได้โดยการนับสัญญาณเพียงอย่างเดียวหรือไม่? ถ้าคุณมีอินสแตนซ์ของทรัพยากร 10 รายการและมี 10 เธรดเข้ามา (ผ่านสัญญาณการนับ) และลองใช้อินสแตนซ์แรก


7

สัญญาณเป็นวัตถุที่มีจำนวนธรรมชาติ (เช่นจำนวนเต็มมากกว่าหรือเท่ากับศูนย์) ที่สองการดำเนินการแก้ไขจะถูกกำหนด การใช้งานครั้งVเดียวเพิ่ม 1 อย่างเป็นธรรมชาติ การดำเนินการอื่นPลดจำนวนธรรมชาติลง 1 กิจกรรมทั้งสองเป็นอะตอมมิก (เช่นไม่มีการดำเนินการอื่นที่สามารถดำเนินการได้ในเวลาเดียวกับ a Vหรือ a P)

เนื่องจากหมายเลขธรรมชาติ 0 ไม่สามารถลดลงได้การเรียกเซPมาฟอร์ที่มี 0 จะบล็อกการดำเนินการของกระบวนการที่เรียก (/ เธรด) จนกระทั่งบางช่วงเวลาที่หมายเลขไม่เป็น 0 อีกต่อไปและPสามารถดำเนินการได้สำเร็จ

ดังที่ได้กล่าวไว้ในคำตอบอื่น ๆ สามารถใช้เซมาฟอร์เพื่อ จำกัด การเข้าถึงทรัพยากรบางอย่างให้ได้มากที่สุด (แต่ตัวแปร) จำนวนกระบวนการ


7

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

ExecutorService executor = Executors.newFixedThreadPool(7);

Semaphore semaphore = new Semaphore(4);

Runnable longRunningTask = () -> {
    boolean permit = false;
    try {
        permit = semaphore.tryAcquire(1, TimeUnit.SECONDS);
        if (permit) {
            System.out.println("Semaphore acquired");
            Thread.sleep(5);
        } else {
            System.out.println("Could not acquire semaphore");
        }
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    } finally {
        if (permit) {
            semaphore.release();
        }
    }
};

// execute tasks
for (int j = 0; j < 10; j++) {
    executor.submit(longRunningTask);
}
executor.shutdown();

เอาท์พุต

Semaphore acquired
Semaphore acquired
Semaphore acquired
Semaphore acquired
Could not acquire semaphore
Could not acquire semaphore
Could not acquire semaphore

โค้ดตัวอย่างจากบทความ


3

การตั้งค่าสถานะฮาร์ดแวร์หรือซอฟต์แวร์ ในระบบมัลติทาสกิ้งเซมาฟอร์นั้นจะเป็นตัวแปรที่มีค่าที่บ่งบอกสถานะของทรัพยากรทั่วไปกระบวนการที่ต้องการให้ทรัพยากรตรวจสอบเซมาฟอร์เพื่อกำหนดสถานะของทรัพยากรแล้วตัดสินใจว่าจะดำเนินการอย่างไร


2

Semaphores ทำหน้าที่เหมือนตัว จำกัด เธรด

ตัวอย่าง:หากคุณมีพูลจำนวน 100 เธรดและคุณต้องการดำเนินการกับฐานข้อมูล หาก 100 เธรดเข้าถึง DB ในเวลาที่กำหนดอาจมีปัญหาการล็อกใน DB เพื่อให้เราสามารถใช้สัญญาณที่อนุญาตเฉพาะเธรดที่ จำกัด ในแต่ละครั้งตัวอย่างด้านล่างอนุญาตหนึ่งเธรดต่อครั้งเท่านั้น เมื่อเธรดเรียกใช้acquire()เมธอดนั้นจะได้รับการเข้าถึงและหลังจากเรียกrelease()เมธอดแล้วเธรดนั้นจะปล่อย acccess เพื่อที่เธรดถัดไปจะได้รับการเข้าถึง

    package practice;
    import java.util.concurrent.Semaphore;

    public class SemaphoreExample {
        public static void main(String[] args) {
            Semaphore s = new Semaphore(1);
            semaphoreTask s1 = new semaphoreTask(s);
            semaphoreTask s2 = new semaphoreTask(s);
            semaphoreTask s3 = new semaphoreTask(s);
            semaphoreTask s4 = new semaphoreTask(s);
            semaphoreTask s5 = new semaphoreTask(s);
            s1.start();
            s2.start();
            s3.start();
            s4.start();
            s5.start();
        }
    }

    class semaphoreTask extends Thread {
        Semaphore s;
        public semaphoreTask(Semaphore s) {
            this.s = s;
        }
        @Override
        public void run() {
            try {
                s.acquire();
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+" Going to perform some operation");
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } 
    }

1

ดังนั้นจินตนาการว่าทุกคนกำลังพยายามเข้าห้องน้ำและมีกุญแจจำนวนหนึ่งเข้าห้องน้ำ ตอนนี้ถ้ามีกุญแจเหลือไม่พอคนนั้นต้องรอ ดังนั้นให้คิดว่าเซมาฟอร์เป็นตัวแทนของชุดคีย์ที่มีให้สำหรับห้องน้ำ (ทรัพยากรระบบ) ที่กระบวนการต่าง ๆ (ผู้ทำห้องน้ำ) สามารถร้องขอการเข้าถึงได้

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

นอกจากนี้ยังมีความแตกต่างระหว่างไบนารี / mutex และเซมาฟอร์นับ

ตรวจสอบเอกสารประกอบการบรรยายที่http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html


0

นี่เป็นคำถามเก่า แต่หนึ่งในการใช้สัญญาณที่น่าสนใจที่สุดอย่างหนึ่งคือล็อคการอ่าน / เขียนและยังไม่ได้กล่าวถึงอย่างชัดเจน

ล็อค r / w ใช้งานง่าย: ใช้ใบอนุญาตหนึ่งใบสำหรับผู้อ่านและใบอนุญาตทั้งหมดสำหรับนักเขียน แท้จริงแล้วการใช้งาน ar / w lock เล็กน้อย แต่ต้องมีการแก้ไขข้อมูลเมตาบนการอ่าน (จริง ๆ แล้วสองครั้ง) ที่สามารถกลายเป็นคอขวดยังคงดีกว่า mutex หรือล็อคอย่างมีนัยสำคัญ

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

อ่านเพิ่มเติม:


-3

สัญญาณส่งสัญญาณเป็นวิธีการล็อคทรัพยากรเพื่อให้มั่นใจได้ว่าในขณะที่ดำเนินการรหัสชิ้นส่วนรหัสเท่านั้นที่มีการเข้าถึงทรัพยากรที่ สิ่งนี้ทำให้เธรดสองเธรดไม่พร้อมใช้งานทรัพยากรซึ่งอาจทำให้เกิดปัญหาได้


13
ฟังดูเหมือน mutex ไม่ใช่เซมาฟอร์
Sam
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.