๐Ÿ˜‡Lock V2

pthread

ไบ’ๆ–ฅ้”ใ€ๆกไปถ้”ใ€่ฏปๅ†™้”ไปฅๅŠ่‡ชๆ—‹้”

้”ๆ˜ฏไธ€ไธชๅธธ่ง็š„ๅŒๆญฅๆฆ‚ๅฟต๏ผŒๆˆ‘ไปฌ้ƒฝๅฌ่ฏด่ฟ‡ๅŠ ้”๏ผˆlock๏ผ‰ๆˆ–่€…่งฃ้”๏ผˆunlock๏ผ‰๏ผŒๅฝ“็„ถๅญฆๆœฏไธ€็‚นๅœฐ่ฏดๆณ•ๆ˜ฏ่Žทๅ–๏ผˆacquire๏ผ‰ๅ’Œ้‡Šๆ”พ๏ผˆrelease๏ผ‰ใ€‚

ๆฐๅฅฝpthreadๅŒ…ๅซ่ฟ™ๅ‡ ็ง้”็š„API๏ผŒ่€ŒC++11ๅชๅŒ…ๅซๅ…ถไธญ็š„้ƒจๅˆ†ใ€‚ๆŽฅไธ‹ๆฅๆˆ‘ๅฐ†้€š่ฟ‡pthread็š„APIๆฅๅฑ•ๅผ€ๅ›ž็ญ”ใ€‚

mutex๏ผˆไบ’ๆ–ฅ้‡๏ผ‰

mutex๏ผˆmutual exclusive๏ผ‰ๅณไบ’ๆ–ฅ้‡๏ผˆไบ’ๆ–ฅไฝ“๏ผ‰ใ€‚ไนŸไพฟๆ˜ฏๅธธ่ฏด็š„ไบ’ๆ–ฅ้”ใ€‚ ๅฐฝ็ฎกๅ็งฐไธๅซlock๏ผŒไฝ†ๆ˜ฏ็งฐไน‹ไธบ้”๏ผŒไนŸๆ˜ฏๆฒกๆœ‰ๅคชๅคง้—ฎ้ข˜็š„ใ€‚

mutexๆ— ็–‘ๆ˜ฏๆœ€ๅธธ่ง็š„ๅคš็บฟ็จ‹ๅŒๆญฅๆ–นๅผใ€‚ๅ…ถๆ€ๆƒณ็ฎ€ๅ•็ฒ—ๆšด๏ผŒๅคš็บฟ็จ‹ๅ…ฑไบซไธ€ไธชไบ’ๆ–ฅ้‡๏ผŒ็„ถๅŽ็บฟ็จ‹ไน‹้—ดๅŽป็ซžไบ‰ใ€‚

ๅพ—ๅˆฐ้”็š„็บฟ็จ‹ๅฏไปฅ่ฟ›ๅ…ฅไธด็•ŒๅŒบๆ‰ง่กŒไปฃ็ ใ€‚

// ๅฃฐๆ˜Žไธ€ไธชไบ’ๆ–ฅ้‡    
pthread_mutex_t mtx;
// ๅˆๅง‹ๅŒ– 
pthread_mutex_init(&mtx, NULL);
// ๅŠ ้”  
pthread_mutex_lock(&mtx);
// ่งฃ้” 
pthread_mutex_unlock(&mtx);
// ้”€ๆฏ
pthread_mutex_destroy(&mtx); 

mutexๆ˜ฏ็ก็œ ็ญ‰ๅพ…๏ผˆsleep waiting๏ผ‰็ฑปๅž‹็š„้”

ๅฝ“็บฟ็จ‹ๆŠขไบ’ๆ–ฅ้”ๅคฑ่ดฅ็š„ๆ—ถๅ€™๏ผŒ็บฟ็จ‹ไผš้™ทๅ…ฅไผ‘็œ ใ€‚

ไผ˜็‚นๅฐฑๆ˜ฏ่Š‚็œCPU่ต„ๆบ๏ผŒ็ผบ็‚นๅฐฑๆ˜ฏไผ‘็œ ๅ”ค้†’ไผšๆถˆ่€—ไธ€็‚นๆ—ถ้—ดใ€‚ๅฆๅค–่‡ชไปŽLinux 2.6็‰ˆไปฅๅŽ๏ผŒmutexๅฎŒๅ…จ็”จfutex็š„APIๅฎž็Žฐไบ†๏ผŒๅ†…้ƒจ็ณป็ปŸ่ฐƒ็”จ็š„ๅผ€้”€ๅคงๅคงๅ‡ๅฐใ€‚

ๅ€ผๅพ—ไธ€ๆ็š„ๆ˜ฏ๏ผŒpthread็š„้”ไธ€่ˆฌ้ƒฝๆœ‰ไธ€ไธชtrylock็š„ๅ‡ฝๆ•ฐ๏ผŒๆฏ”ๅฆ‚ๅฏนไบŽไบ’ๆ–ฅ้‡๏ผš

ret = pthread_mutex_trylock(&mtx);
if (0 == ret) { // ๅŠ ้”ๆˆๅŠŸ
    ... 
    pthread_mutex_unlock(&mtx);
} else if (EBUSY == ret) { // ้”ๆญฃๅœจ่ขซไฝฟ็”จ;
    ... 
}

pthread_mutex_trylock็”จไบŽไปฅ้ž้˜ปๅกž็š„ๆจกๅผๆฅ่ฏทๆฑ‚ไบ’ๆ–ฅ้‡ใ€‚ๅฐฑๅฅฝๆฏ”ๅ„็งIOๅ‡ฝๆ•ฐ้ƒฝๆœ‰ไธ€ไธชnoblock็š„ๆจกๅผไธ€ๆ ท๏ผŒๅฏนไบŽๅŠ ้”่ฟ™ไปถไบ‹ไนŸๆœ‰็ฑปไผผ็š„้ž้˜ปๅกžๆจกๅผใ€‚

ๅฝ“็บฟ็จ‹ๅฐ่ฏ•ๅŠ ้”ๆ—ถ๏ผŒๅฆ‚ๆžœ้”ๅทฒ็ป่ขซๅ…ถไป–็บฟ็จ‹้”ๅฎš๏ผŒ่ฏฅ็บฟ็จ‹ๅฐฑไผš้˜ปๅกžไฝ๏ผŒ็›ดๅˆฐ่ƒฝๆˆๅŠŸacquireใ€‚ไฝ†ๆœ‰ๆ—ถๅ€™ๆˆ‘ไปฌไธๅธŒๆœ›่ฟ™ๆ ทใ€‚pthread_mutex_trylockๅœจ่ขซๅ…ถไป–็บฟ็จ‹้”ๅฎšๆ—ถ๏ผŒไผš่ฟ”ๅ›ž็‰นๆฎŠ้”™่ฏฏ็ ใ€‚ๅŠ ้”ๆˆ่ฟ”ๅ›ž0๏ผŒไป…ๅฝ“ๆˆๅŠŸไฝ†ๆ—ถๅ€™๏ผŒๆˆ‘ไปฌๆ‰่ƒฝ่งฃ้”ๅœจๅŽ้ข่ฟ›่กŒ่งฃ้”ๆ“ไฝœ๏ผ

C++11ๅผ€ๅง‹ๅผ•ๅ…ฅไบ†ๅคš็บฟ็จ‹ๅบ“๏ผŒๅ…ถไธญไนŸๅŒ…ๅซไบ†ไบ’ๆ–ฅ้”็š„API๏ผšstd::mutex ใ€‚

ๆญคๅค–๏ผŒไพๆฎๅŒไธ€็บฟ็จ‹ๆ˜ฏๅฆ่ƒฝๅคšๆฌกๅŠ ้”๏ผŒๆŠŠไบ’ๆ–ฅ้‡ๅˆๅˆ†ไธบๅฆ‚ไธ‹ไธค็ฑป๏ผš

  • ๆ˜ฏ๏ผš็งฐไธบใ€Ž้€’ๅฝ’ไบ’ๆ–ฅ้‡ใ€recursive mutex ๏ผŒไนŸ็งฐใ€Žๅฏ้‡ๅ…ฅ้”ใ€reentrant lock

  • ๅฆ๏ผšๅณใ€Ž้ž้€’ๅฝ’ไบ’ๆ–ฅ้‡ใ€non-recursive mute๏ผ‰๏ผŒไนŸ็งฐใ€Žไธๅฏ้‡ๅ…ฅ้”ใ€non-reentrant mutex

่‹ฅๅŒไธ€็บฟ็จ‹ๅฏน้ž้€’ๅฝ’็š„ไบ’ๆ–ฅ้‡ๅคšๆฌกๅŠ ้”๏ผŒๅฏ่ƒฝไผš้€ ๆˆๆญป้”ใ€‚้€’ๅฝ’ไบ’ๆ–ฅ้‡ๅˆ™ๆ— ๆญค้ฃŽ้™ฉใ€‚C++11ไธญๆœ‰้€’ๅฝ’ไบ’ๆ–ฅ้‡็š„API๏ผšstd::recursive_mutexใ€‚ๅฏนไบŽpthreadๅˆ™ๅฏไปฅ้€š่ฟ‡็ป™mutexๆทปๅŠ PTHREAD_MUTEX_RECURSIVE ๅฑžๆ€ง็š„ๆ–นๅผๆฅไฝฟ็”จ้€’ๅฝ’ไบ’ๆ–ฅ้‡๏ผš

// ๅฃฐๆ˜Žไธ€ไธชไบ’ๆ–ฅ้‡
pthread_mutex_t mtx;
// ๅฃฐๆ˜Žไธ€ไธชไบ’ๆ–ฅ้‡็š„ๅฑžๆ€งๅ˜้‡
pthread_mutexattr_t mtx_attr;

// ๅˆๅง‹ๅŒ–ไบ’ๆ–ฅ้‡็š„ๅฑžๆ€งๅ˜้‡
pthread_mutexattr_init(&mtx_attr);
// ่ฎพ็ฝฎ้€’ๅฝ’ไบ’ๆ–ฅ้‡็š„ๅฑžๆ€ง
pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_RECURSIVE);

// ๆŠŠๅฑžๆ€ง่ต‹ๅ€ผ็ป™ไบ’ๆ–ฅ้‡
pthread_mutext_init(&mtx, &mutext_attr);

็„ถ่€ŒๅฏนไบŽ้€’ๅฝ’ไบ’ๆ–ฅ้‡ๆˆ–่€…่ฏดๅฏ้‡ๅ…ฅ้”็š„ไฝฟ็”จๅˆ™้œ€่ฆๅ…‹ๅˆถใ€‚Stevensๅคง็ฅž็”Ÿๅ‰ๅœจใ€ŠAPUEใ€‹ไธญ่ฏดใ€Žไฝฟ็”จๅฅฝๅฎƒๆ˜ฏๅๅˆ†tricky็š„๏ผŒไป…ๅฝ“ๆฒกๆœ‰ๅ…ถไป–่งฃๅ†ณๆ–นๆกˆๆ—ถๆ‰ไฝฟ็”จใ€[1]ใ€‚

ๅฏ้‡ๅ…ฅ้”่ฟ™ไธชๆฆ‚ๅฟตๅ’Œ็งฐๅ‘ผ็š„่ตฐไฟๅคšๅŠๆ˜ฏJava่ฏญ่จ€็š„ๅŠŸๅŠณใ€‚

condition variable๏ผˆๆกไปถๅ˜้‡๏ผ‰

้ข˜ไธปๆ‰€่ฐ“็š„ๆกไปถ้”๏ผŒๆˆ‘็ŒœๆŒ‡็š„ๅบ”่ฏฅๆ˜ฏๆกไปถๅ˜้‡ใ€‚่ฏทๆณจๆ„ๆกไปถๅ˜้‡ไธๆ˜ฏ้”๏ผŒๅฎƒๆ˜ฏไธ€็ง็บฟ็จ‹้—ด็š„้€š่ฎฏๆœบๅˆถ๏ผŒๅนถไธ”ๅ‡ ไนŽๆ€ปๆ˜ฏๅ’Œไบ’ๆ–ฅ้‡ไธ€่ตทไฝฟ็”จ็š„ใ€‚ๆ‰€ไปฅไบ’ๆ–ฅ้‡ๅ’Œๆกไปถๅ˜้‡ไบŒ่€…ไธ€่ˆฌๆ˜ฏๆˆๅฅ—ๅ‡บ็Žฐ็š„ใ€‚ๆฏ”ๅฆ‚C++11ไธญไนŸๆœ‰ๆกไปถๅ˜้‡็š„API๏ผš std::condition_variableใ€‚

ๅฏนไบŽpthread๏ผš

// ๅฃฐๆ˜Žไธ€ไธชไบ’ๆ–ฅ้‡     
pthread_mutex_t mtx;
// ๅฃฐๆ˜Žไธ€ไธชๆกไปถๅ˜้‡
pthread_cond_t cond;
...

// ๅˆๅง‹ๅŒ– 
pthread_mutex_init(&mtx, NULL);
pthread_cond_init(&cond, NULL);

// ๅŠ ้”  
pthread_mutex_lock(&mtx);
// ๅŠ ้”ๆˆๅŠŸ๏ผŒ็ญ‰ๅพ…ๆกไปถๅ˜้‡่งฆๅ‘
pthread_cond_wait(&cond, &mtx);

...
// ๅŠ ้”  
pthread_mutex_lock(&mtx);
pthread_cond_signal(&cond);
...

// ่งฃ้” 
pthread_mutex_unlock(&mtx);
// ้”€ๆฏ
pthread_mutex_destroy(&mtx);

pthread_cond_waitๅ‡ฝๆ•ฐไผšๆŠŠๆกไปถๅ˜้‡ๅ’Œไบ’ๆ–ฅ้‡้ƒฝไผ ๅ…ฅใ€‚ๅนถไธ”ๅคš็บฟ็จ‹่ฐƒ็”จ็š„ๆ—ถๅ€™ๆกไปถๅ˜้‡ๅ’Œไบ’ๆ–ฅ้‡ไธ€ๅฎš่ฆไธ€ไธ€ๅฏนๅบ”๏ผŒไธ่ƒฝไธ€ไธชๆกไปถๅ˜้‡ๅœจไธๅŒ็บฟ็จ‹ไธญwait็š„ๆ—ถๅ€™ไผ ๅ…ฅไธๅŒ็š„ไบ’ๆ–ฅ้‡ใ€‚ๅฆๅˆ™ๆ˜ฏๆœชๅฎšไน‰็ป“ๆžœใ€‚

ๅ…ณไบŽๆ˜ฏๅ…ˆ่งฃ้”ไบ’ๆ–ฅ้‡่ฟ˜ๆ˜ฏๅ…ˆ่ฟ›่กŒๆกไปถๅ˜้‡็š„้€š็Ÿฅ๏ผŒๆ˜ฏๅฆๅค–ไธ€ไธชๆฏ”่พƒๅคง็š„่ฎฎ้ข˜ใ€‚ๆœ‰็ง่ฎบๆ–ญ่ฏด๏ผšๅ…ˆ่งฃ้”ไบ’ๆ–ฅ้‡ๅ†้€š็Ÿฅๆกไปถๅ˜้‡ๅฏไปฅๅ‡ๅฐ‘ๅคšไฝ™็š„ไธŠไธ‹ๆ–‡ๅˆ‡ๆข๏ผŒ่ฟ›่€Œๆ้ซ˜ๆ•ˆ็Ž‡ใ€‚่ฟ™็ง่ฏดๆณ•ๆ˜ฏๅŸบไบŽไธ€็งๅฎž็Žฐๅ‡่ฎพ๏ผšๅ…ˆ้€š็Ÿฅๆกไปถๅ˜้‡๏ผŒๅ†่งฃ้”ใ€‚ๅฏ่ƒฝ่ฎฉๅ…ถไป–็ญ‰ๅพ…ๆกไปถๅ˜้‡็š„็บฟ็จ‹่ขซๅ”ค้†’ไบ†๏ผŒไฝ†ๆ˜ฏๆญคๆ—ถไบ’ๆ–ฅ้‡่ฟ˜ๆฒก่งฃ้”๏ผŒไปŽ่€Œๅ†ๆฌก้™ทๅ…ฅไผ‘็œ ใ€‚็„ถ่€ŒๅฏนไบŽๅฆๅค–ไธ€ไบ›ๅฎž็Žฐ๏ผŒๆฏ”ๅฆ‚Linux็ณป็ปŸ๏ผŒๅˆ™้€š่ฟ‡็ญ‰ๅพ…ๅ˜ๅฝข๏ผˆwait morphing๏ผ‰[2]่งฃๅ†ณไบ†่ฟ™ไธ€้—ฎ้ข˜ใ€‚ๆ‰€ไปฅๅ…ˆ้€š็Ÿฅๅ†่งฃ้”ไนŸๆฒก็”จ้—ฎ้ข˜ใ€‚

ๅฆๅค–ๅœจไฝฟ็”จๆกไปถๅ˜้‡็š„่ฟ‡็จ‹ไธญๆœ‰ไธช็จๅพฎ่ฟๅ็›ด่ง‰็š„ๅ†™ๆณ•๏ผš้‚ฃๅฐฑๆ˜ฏไฝฟ็”จwhile่€Œไธๆ˜ฏifๆฅๅšๅˆคๆ–ญ็Šถๆ€ๆ˜ฏๅฆๆปก่ถณใ€‚่ฟ™ๆ ทๅš็š„ๅŽŸๅ› ๆœ‰ไบŒ๏ผš

  1. ้ฟๅ…ๆƒŠ็พค๏ผ›

  2. ้ฟๅ…ๆŸไบ›ๆƒ…ๅ†ตไธ‹็บฟ็จ‹่ขซ่™šๅ‡ๅ”ค้†’๏ผˆๅณๆฒกๆœ‰pthread_cond_signalๅฐฑ่งฃ้™คไบ†้˜ปๅกž๏ผ‰ใ€‚

ๆฏ”ๅฆ‚ๅŠๅŒๆญฅ/ๅŠreactor็š„็ฝ‘็ปœๆจกๅž‹ไธญ๏ผŒๅœจๅทฅไฝœ็บฟ็จ‹ๆถˆ่ดนfd้˜Ÿๅˆ—็š„ๆ—ถๅ€™๏ผš

while (1) {
    if (pthread_mutex_lock(&mtx) != 0) { // ๅŠ ้”
        ... // ๅผ‚ๅธธ้€ป่พ‘
    }
    while (queue.empty()) {
        if (pthread_cond_wait(&cond, &mtx) != 0) {
            ... // ๅผ‚ๅธธ้€ป่พ‘
        }
    }
    auto data = queue.pop();
    if (pthread_mutex_unlock(&mtx) != 0) { // ่งฃ้”
        ... // ๅผ‚ๅธธ้€ป่พ‘
    }
    process(data); // ๅค„็†ๆต็จ‹๏ผŒไธšๅŠก้€ป่พ‘
}

read-write lock๏ผˆ่ฏปๅ†™้”๏ผ‰

้กพๅๆ€ไน‰ใ€Ž่ฏปๅ†™้”ใ€ๅฐฑๆ˜ฏๅฏนไบŽไธด็•ŒๅŒบๅŒบๅˆ†่ฏปๅ’Œๅ†™ใ€‚ๅœจ่ฏปๅคšๅ†™ๅฐ‘็š„ๅœบๆ™ฏไธ‹๏ผŒไธๅŠ ๅŒบๅˆ†็š„ไฝฟ็”จไบ’ๆ–ฅ้‡ๆ˜พ็„ถๆ˜ฏๆœ‰็‚นๆตช่ดน็š„ใ€‚ๆญคๆ—ถไพฟ่ฏฅไธŠๆผ”่ฏปๅ†™้”็š„ๆ‹ฟๆ‰‹ๅฅฝๆˆใ€‚

่ฏปๅ†™้”ๆœ‰ไธ€ไธชๅˆซ็งฐๅซใ€Žๅ…ฑไบซ-็‹ฌๅ ้”ใ€ใ€‚ไธ่ฟ‡ๅ•็œ‹ใ€Žๅ…ฑไบซ-็‹ฌๅ ้”ใ€ๆˆ–่€…ใ€Ž่ฏปๅ†™้”ใ€่ฟ™ไธคไธชๅ็งฐ๏ผŒๅ…ถๅฎžๅนถๆœชๅŒบๅˆ†ๅฏนไบŽ่ฏปๅ’Œๅ†™๏ผŒๅˆฐๅบ•่ฐๅ…ฑไบซ๏ผŒ่ฐ็‹ฌๅ ใ€‚ๅฏ่ƒฝไผš่ฎฉไบบ่ฏฏไปฅไธบ่ฏปๅ†™้”ๆ˜ฏไธ€็งๆ›ดไธบๆณ›ๅŒ–็š„็งฐๅ‘ผ๏ผŒๅ…ถๅฎžไธๆ˜ฏใ€‚่ฏปๅ†™้”็š„ๅซไน‰ๆ˜ฏๅ‡†็กฎ็š„๏ผšๆ˜ฏไธ€็ง ่ฏปๅ…ฑไบซ๏ผŒๅ†™็‹ฌๅ ็š„้”ใ€‚

่ฏปๅ†™้”็š„็‰นๆ€ง๏ผš

  • ๅฝ“่ฏปๅ†™้”่ขซๅŠ ไบ†ๅ†™้”ๆ—ถ๏ผŒๅ…ถไป–็บฟ็จ‹ๅฏน่ฏฅ้”ๅŠ ่ฏป้”ๆˆ–่€…ๅ†™้”้ƒฝไผš้˜ปๅกž๏ผˆไธๆ˜ฏๅคฑ่ดฅ๏ผ‰ใ€‚

  • ๅฝ“่ฏปๅ†™้”่ขซๅŠ ไบ†่ฏป้”ๆ—ถ๏ผŒๅ…ถไป–็บฟ็จ‹ๅฏน่ฏฅ้”ๅŠ ๅ†™้”ไผš้˜ปๅกž๏ผŒๅŠ ่ฏป้”ไผšๆˆๅŠŸใ€‚

ๅ› ่€Œ้€‚็”จไบŽๅคš่ฏปๅฐ‘ๅ†™็š„ๅœบๆ™ฏใ€‚

// ๅฃฐๆ˜Žไธ€ไธช่ฏปๅ†™้”
pthread_rwlock_t rwlock;
...
// ๅœจ่ฏปไน‹ๅ‰ๅŠ ่ฏป้”
pthread_rwlock_rdlock(&rwlock);

... ๅ…ฑไบซ่ต„ๆบ็š„่ฏปๆ“ไฝœ

// ่ฏปๅฎŒ้‡Šๆ”พ้”
pthread_rwlock_unlock(&rwlock);

// ๅœจๅ†™ไน‹ๅ‰ๅŠ ๅ†™้”
pthread_rwlock_wrlock(&rwlock); 

... ๅ…ฑไบซ่ต„ๆบ็š„ๅ†™ๆ“ไฝœ

// ๅ†™ๅฎŒ้‡Šๆ”พ้”
pthread_rwlock_unlock(&rwlock);

// ้”€ๆฏ่ฏปๅ†™้”
pthread_rwlock_destroy(&rwlock);

ๅ…ถๅฎžๅŠ ่ฏป้”ๅ’ŒๅŠ ๅ†™้”่ฟ™ไธคไธช่ฏดๆณ•ๅฏ่ƒฝไผš้€ ๆˆ่ฏฏๅฏผ๏ผŒ่ฎฉไบบ่ฏฏไปฅไธบๆ˜ฏๆœ‰ไธคๆŠŠ้”๏ผŒๅ…ถๅฎž่ฏปๅ†™้”ๆ˜ฏไธ€ไธช้”ใ€‚ๆ‰€่ฐ“ๅŠ ่ฏป้”ๅ’ŒๅŠ ๅ†™้”๏ผŒๅ‡†็กฎ็š„่ฏดๆณ•ๅฏ่ƒฝๆ˜ฏใ€Ž็ป™่ฏปๅ†™้”ๅŠ ่ฏปๆจกๅผ็š„้”ๅฎšๅ’ŒๅŠ ๅ†™ๆจกๅผ็š„้”ๅฎšใ€ใ€‚

่ฏปๅ†™้”ๅ’Œไบ’ๆ–ฅ้‡ไธ€ๆ ทไนŸๆœ‰trylockๅ‡ฝๆ•ฐ๏ผŒไนŸๆ˜ฏไปฅ้ž้˜ปๅกžๅœฐๅฝขๅผๆฅ่ฏทๆฑ‚้”๏ผŒไธไผšๅฏผ่‡ด้˜ปๅกžใ€‚

 pthread_rwlock_tryrdlock(&rwlock)
 pthread_rwlock_trywrlock(&rwlock)

C++11ไธญๆœ‰ไบ’ๆ–ฅ้‡ใ€ๆกไปถๅ˜้‡ไฝ†ๆ˜ฏๅนถๆฒกๆœ‰ๅผ•ๅ…ฅ่ฏปๅ†™้”ใ€‚่€ŒๅœจC++17ไธญๅ‡บ็Žฐไบ†ไธ€็งๆ–ฐ้”๏ผšstd::shared_mutexใ€‚็”จๅฎƒๅฏไปฅๆจกๆ‹Ÿๅฎž็Žฐๅ‡บ่ฏปๅ†™้”ใ€‚demoไปฃ็ ๅฏไปฅ็›ดๆŽฅๅ‚่€ƒcppreference๐Ÿ‘‡๏ผš

std::shared_mutex - cppreference.comen.cppreference.com/w/cpp/thread/shared_mutex

ๅฆๅค–ๅคš่ฏปๅฐ‘ๅ†™็š„ๅœบๆ™ฏๆœ‰ไบ›็‰นๆฎŠๅœบๆ™ฏ๏ผŒๅฏไปฅ็”จ็‰นๆฎŠ็š„ๆ•ฐๆฎ็ป“ๆž„ๅ‡ๅฐ‘้”ไฝฟ็”จ๏ผš

  • ๅคš่ฏปๅ•ๅ†™็š„็บฟๆ€งๆ•ฐๆฎใ€‚็”จๆ•ฐ็ป„ๅฎž็Žฐ็Žฏๅฝข้˜Ÿๅˆ—๏ผŒ้ฟๅ…vector็ญ‰ๅŠจๆ€ๆ‰ฉๅผ ็š„ๆ•ฐๆฎ็ป“ๆž„๏ผŒๅ†™ๅœจ็ป“ๅฐพ๏ผŒ็”ฑไบŽๅ•ๅ†™ๅ› ่€ŒๅฏไปฅไธๅŠ ้”๏ผ›่ฏปๅœจๅผ€ๅคด๏ผŒ็”ฑไบŽๅคš่ฏป๏ผˆ้ฟๅ…้‡ๅคๆถˆ่ดน๏ผ‰ๆ‰€ไปฅ้œ€่ฆๅŠ ไธ€ไธ‹้”๏ผˆไบ’ๆ–ฅ้‡ๅฐฑ่กŒ๏ผ‰ใ€‚

  • ๅคš่ฏปๅ•ๅ†™็š„KVใ€‚ๅฏไปฅไฝฟ็”จๅŒ็ผ“ๅ†ฒ๏ผˆdouble buffer๏ผ‰็š„ๆ•ฐๆฎ็ป“ๆž„ๆฅๅฎž็Žฐใ€‚double bufferๅŒๅ็š„ๆฆ‚ๅฟตๆฏ”่พƒๅคš๏ผŒ่ฟ™้‡ŒๆŒ‡็š„ๆ˜ฏforeground ๅ’Œ backgroud ไธคไธชbuffer่ฟ›่กŒๅˆ‡ๆข็š„ใ€Ž0 - 1ๅˆ‡ๆขใ€ๆŠ€ๆœฏใ€‚ๆฏ”ๅฆ‚ๅฎž็ŽฐๅŠจๆ€ๅŠ ่ฝฝ๏ผˆ็ƒญๅŠ ่ฝฝ๏ผ‰้…็ฝฎๆ–‡ไปถ็š„ๆ—ถๅ€™ใ€‚ๅฏ่ƒฝไผšๅœจๅˆ‡ๆข้—ด้š™ๅŠ ไธ€ไธช็Ÿญๆš‚็š„ไบ’ๆ–ฅ้‡๏ผŒไฝ†ๆ˜ฏๅŸบๆœฌๅฏไปฅ่ฎคไธบๆ˜ฏlock free็š„ใ€‚

ๆˆ‘ไธ€ๅผ ๅฃ๏ผŒไฝ ๅฐฑไผšๅ‘็Žฐ๏ผšๆ— ้žไนŸๅฐฑๆ˜ฏ็ฉบ้—ดๆขๆ—ถ้—ด็š„่€ๅฅ—่ทฏไบ†ใ€‚

spinlock๏ผˆ่‡ชๆ—‹้”๏ผ‰

่‡ชๆ—‹ไน‹ๅ้ข‡ไธบ็Ž„ๅฆ™๏ผŒ็ฌฌไธ€ๆฌกๅฌ้—ปๅธธ่ฎฉไบบ็•ฅ่ง‰้ซ˜ๅคงใ€‚ไฝ†ๅ’Œๆ— ๆ•ฐไธชๅฅฝไผผใ€Žๆ•…ๆ„ๆŠŠ็ฎ€ๅ•ๆฆ‚ๅฟตๅคๆ‚ๅŒ–ใ€็š„่ฎก็ฎ—ๆœบๆœฏ่ฏญไธ€ๆ ท๏ผŒ่‡ชๆ—‹้”็š„ๆœฌ่ดจ็ฎ€ๅ•็š„้šพไปฅ็ฝฎไฟกใ€‚

่ฆไบ†่งฃ่‡ชๆ—‹้”๏ผŒ้ฆ–ๅ…ˆไบ†่งฃ่‡ชๆ—‹ใ€‚ไป€ไนˆๆ˜ฏ่‡ชๆ—‹๏ผˆspin๏ผ‰ๅ‘ข๏ผŸๆ›ดไธบ้€šไฟ—็š„ไธ€ไธช่ฏๆ˜ฏใ€Žๅฟ™็ญ‰ๅพ…ใ€๏ผˆbusy waiting๏ผ‰ใ€‚ๆœ€ๆœ€้€šไฟ—็š„ไธ€ไธช็†่งฃ๏ผŒๅ…ถๅฎžๅฐฑๆ˜ฏๆญปๅพช็Žฏโ€ฆโ€ฆใ€‚

ๅ•็œ‹ไฝฟ็”จๆ–นๆณ•ๅ’Œไฝฟ็”จไบ’ๆ–ฅ้‡็š„ไปฃ็ ๆ˜ฏๅทฎไธๅคš็š„ใ€‚ๅชไธ่ฟ‡่‡ชๆ—‹้”ไธไผšๅผ•่ตท็บฟ็จ‹ไผ‘็œ ใ€‚ๅฝ“ๅ…ฑไบซ่ต„ๆบ็š„็Šถๆ€ไธๆปก่ถณ็š„ๆ—ถๅ€™๏ผŒ่‡ชๆ—‹้”ไผšไธๅœๅœฐๅพช็Žฏๆฃ€ๆต‹็Šถๆ€ใ€‚ๅ› ไธบไธไผš้™ทๅ…ฅไผ‘็œ ๏ผŒ่€Œๆ˜ฏๅฟ™็ญ‰ๅพ…็š„ๆ–นๅผไนŸๅฐฑไธ้œ€่ฆๆกไปถๅ˜้‡ใ€‚

่ฟ™ๆ˜ฏไผ˜็‚นไนŸๆ˜ฏ็ผบ็‚นใ€‚ไธไผ‘็œ ๅฐฑไธไผšๅผ•่ตทไธŠไธ‹ๆ–‡ๅˆ‡ๆข๏ผŒไฝ†ๆ˜ฏไผšๆฏ”่พƒๆตช่ดนCPUใ€‚

// ๅฃฐๆ˜Žไธ€ไธช่‡ชๆ—‹้”ๅ˜้‡
pthread_spinlock_t spinlock;

// ๅˆๅง‹ๅŒ–   
pthread_spin_init(&spinlock, 0);

// ๅŠ ้”  
pthread_spin_lock(&spinlock);

// ่งฃ้” 
pthread_spin_unlock(&spinlock);

// ้”€ๆฏ  
pthread_spin_destroy(&spinlock);

pthread_spin_initๅ‡ฝๆ•ฐ็š„็ฌฌไบŒไธชๅ‚ๆ•ฐๅไธบpshared๏ผˆint็ฑปๅž‹๏ผ‰ใ€‚่กจ็คบ็š„ๆ˜ฏๆ˜ฏๅฆ่ƒฝ่ฟ›็จ‹้—ดๅ…ฑไบซ่‡ชๆ—‹้”ใ€‚่ฟ™่ขซ็งฐไน‹ไธบThread Process-Shared Synchronizationใ€‚ไบ’ๆ–ฅ้‡็š„้€š่ฟ‡ๅฑžๆ€งไนŸๅฏไปฅๆŠŠไบ’ๆ–ฅ้‡่ฎพ็ฝฎๆˆ่ฟ›็จ‹้—ดๅ…ฑไบซ็š„ใ€‚psharedๆœ‰ไธคไธชๆžšไธพๅ€ผ๏ผš

  • PTHREAD_PROCESS_PRIVATE๏ผšไป…ๅŒ่ฟ›็จ‹ไธ‹่ฏป็บฟ็จ‹ๅฏไปฅไฝฟ็”จ่ฏฅ่‡ชๆ—‹้”

  • PTHREAD_PROCESS_SHARED๏ผšไธๅŒ่ฟ›็จ‹ไธ‹็š„็บฟ็จ‹ๅฏไปฅไฝฟ็”จ่ฏฅ่‡ชๆ—‹้”

**ๅœจLinuxไธŠ็š„glibcไธญ่ฟ™ไธคไธชๆžšไธพๅ€ผๅˆ†ๅˆซๆ˜ฏ0ๅ’Œ1๏ผˆMacไธŠไธๆ˜ฏ๏ผ‰ใ€‚ๆ‰€ไปฅ้€šๅธธไนŸไผš็œ‹ๅˆฐ็›ดๆŽฅไผ 0็š„ไปฃ็ ใ€‚ไฝ ๅฏ่ƒฝ่ง‰ๅพ—ไธไฝฟ็”จๅฎ๏ผŒ็›ดๆŽฅ็”จๆ•ฐๅญ—็กฌ็ผ–็ ไธๆ˜ฏไธ€ไธชๅฅฝไน ๆƒฏใ€‚็š„็กฎ๏ผŒๅฆฅๅฆฅ็š„Magic Number๏ผŒไฝ†่ฟ˜ๆœ‰ไธ€ไธชๆœ‰่ถฃ็š„ไบ‹ๅฎžไฝ ้œ€่ฆไบ†่งฃ๏ผš**ๅนถไธๆ˜ฏๆ‰€ๆœ‰ๅฎž็Žฐ้ƒฝๆ”ฏๆŒ่‡ชๆ—‹้”่ฎพ็ฝฎไธค็งpsharedใ€‚ๆฏ”ๅฆ‚[3]๏ผš

int pthread_spin_init (pthread_spinlock_t *lock, int pshared) {
    /* Relaxed MO is fine because this is an initializing store.  */
    atomic_store_relaxed (lock, 0);
    return0;
}

ๆ‰€ไปฅ็›ดๆŽฅไผ 0ๅฏ่ƒฝไนŸๆ— ไผคๅคง้›…ใ€‚

่‡ชๆ—‹้” VS ไบ’ๆ–ฅ้‡+ๆกไปถๅ˜้‡ ๅญฐไผ˜ๅญฐๅŠฃ๏ผŸ่‚ฏๅฎš่ฆ็œ‹ๅ…ทไฝ“็š„ไฝฟ็”จๅœบๆ™ฏใ€‚

ๅฝ“ไฝ ไธ็Ÿฅ้“ๅœจไฝ ็š„ไฝฟ็”จๅœบๆ™ฏไธ‹่ฟ™ไธค็ง้”่ฏฅ็”จๅ“ชไธช็š„ๆ—ถๅ€™๏ผŒ้‚ฃๅฐฑๆ˜ฏ็”จไบ’ๆ–ฅ้‡ๅง๏ผๆˆ–่€…้€š่ฟ‡ๅŽ‹ๆต‹็š„ๅˆคๆ–ญ๏ผŒไธ่ฟ‡ๅคงๅคšๆ•ฐๆ—ถๅ€™ๆˆ‘ไปฌๅฅฝๅƒๅนถไธ้œ€่ฆ่ฟ™ไนˆไธ€ไธชpthread็š„่‡ชๆ—‹้”๏ผŒ็Ÿฅๅ‹ไปฌๅฏไปฅๆไพ›ไธ€ไบ›่‡ชๆ—‹้”็š„ไฝฟ็”จๅ‚่€ƒใ€‚

ๅ†…ๅฎนๅคชๅคš๏ผŒ้šพๅ…ๆœ‰่ฏฏ๏ผŒๆœ›ๅคงๅฎถๆŒ‡ๆ•™ใ€‚

ๅ‚่€ƒ

  1. ^1 https://en.wikipedia.org/wiki/Reentrant_mutex#Practical_use

  2. ^2 [https://books.google.com.hk/books?id=Ps2SH727eCIC&pg=PA647&lpg=PA647&dq=linux+programming+interface+wait+morphing&source=bl&ots=kMKcz2zPC7&sig=ACfU3U1ZSbxBegrQhuVkfNAMTRkY-YavvA&hl=en&sa=X&redir_esc=y&hl=zh-CN&sourceid=cndr#v=onepage&q=linux%20programming%20interface%20wait%20morphing&f=false](https://books.google.com.hk/books?id=Ps2SH727eCIC&pg=PA647&lpg=PA647&dq=linux+programming+interface+wait+morphing&source=bl&ots=kMKcz2zPC7&sig=ACfU3U1ZSbxBegrQhuVkfNAMTRkY-YavvA&hl=en&sa=X&redir_esc=y&hl=zh-CN&sourceid=cndr#v=onepage&q=linux programming interface wait morphing&f=false)

  3. ^3 https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/nptl/pthread_spin_init.c

C++11

Last updated