2012-06-20 15 views
7

tôi thấy mã spinlock sau trong boost::smart_ptr:sự khác biệt giữa pthread_spinlock và tăng :: smart_ptr :: spinlock?

bool try_lock() 
{ 
    return (__sync_lock_test_and_set(&v_, 1) == 0); 
} 
void lock() 
{  
    for (unsigned k=0; !try_lock(); ++k) 
    { 
     if (k<4) 
      ; // spin 
     else if (k < 16) 
      __asm__ __volatile__("pause"); // was ("rep; nop" ::: "memory") 
     else if (k < 32 || k & 1) 
      sched_yield(); 
     else 
     { 
      struct timespec rqtp; 
      rqtp.tv_sec = 0; 
      rqtp.tv_nsec = 100; 
      nanosleep(&rqtp, 0); 
     } 
    } 
} 
void unlock() 
{ 
    __sync_lock_release(&v_); 
} 

Vì vậy, nếu tôi hiểu điều này một cách chính xác, khi khóa được tranh luận các chủ đề đến theo cấp số nhân sẽ back-off, đầu tiên quay một cách hoang dại, sau đó dừng lại, sau đó năng suất thời gian còn lại thời gian của nó lát, và cuối cùng lật-flopping giữa ngủ và năng suất.

Tôi cũng đã tìm thấy cài đặt glibc pthread_spinlock, sử dụng lắp ráp để thực hiện khóa.

#define LOCK_PREFIX "lock;" // using an SMP machine 

int pthread_spin_lock(pthread_spinlock_t *lock) 
{ 
    __asm__ ("\n" 
     "1:\t" LOCK_PREFIX "decl %0\n\t" 
     "jne 2f\n\t" 
     ".subsection 1\n\t" 
     ".align 16\n" 
     "2:\trep; nop\n\t" 
     "cmpl $0, %0\n\t" 
     "jg 1b\n\t" 
     "jmp 2b\n\t" 
     ".previous" 
     : "=m" (*lock) 
     : "m" (*lock)); 

    return 0; 
} 

Tôi sẽ thừa nhận rằng sự hiểu biết của tôi về lắp ráp không tốt, vì vậy tôi không hiểu đầy đủ về những gì đang xảy ra ở đây. (Ai đó có thể vui lòng giải thích điều này đang làm gì?)

Tuy nhiên, tôi chạy một số xét nghiệm so với tăng spinlock và glibc pthread_spinlock, và khi có nhiều lõi hơn đề, mã tăng nhanh hơn so với mã glibc.

Mặt khác, Khi có nhiều hơn chủ đề nhiều hơn lõi, mã glibc là tốt hơn.

Tại sao điều này? Sự khác biệt giữa hai triển khai spinlock này làm cho chúng hoạt động khác nhau trong từng kịch bản là gì?

+0

Hài hước, tôi đã thực hiện một thử nghiệm tương tự cách đây vài năm và nhận được kết luận tương tự: 'pthread_spin_lock' hiệu quả hơn so với vòng quay thủ công (dòng từ tăng) khi có nhiều tranh chấp. –

Trả lời

5

Bạn đã thực hiện triển khai pthread_spin_lock() được đăng trong câu hỏi ở đâu? Dường như thiếu một vài dòng quan trọng.

Việc thực hiện tôi thấy (mà không phải là lắp ráp nội tuyến - đó là một tập tin nguồn lắp ráp độc lập từ glibc/nptl/sysdeps/i386/pthread_spin_lock.S) trông giống nhau, nhưng có hai hướng dẫn bổ sung quan trọng:

#include <lowlevellock.h> 

    .globl pthread_spin_lock 
    .type pthread_spin_lock,@function 
    .align 16 
pthread_spin_lock: 
    mov 4(%esp), %eax 
1: LOCK 
    decl 0(%eax) 
    jne 2f 
    xor %eax, %eax 
    ret 

    .align 16 
2: rep 
    nop 
    cmpl $0, 0(%eax) 
    jg 1b 
    jmp 2b 
    .size pthread_spin_lock,.-pthread_spin_lock 

Nó decrements một long nhọn đến bởi tham số được truyền vào và trả về nếu kết quả bằng không.

Nếu không, kết quả không khác có nghĩa là luồng này không có khóa. Vì vậy, nó thực hiện một rep nop, tương đương với hướng dẫn pause. Đây là một nop 'đặc biệt' đưa ra một gợi ý cho CPU rằng luồng nằm trong vòng quay, và cpu sẽ xử lý thứ tự bộ nhớ và/hoặc prdiction chi tiết theo cách nào đó để cải thiện hiệu suất trong những tình huống này (tôi không giả vờ hiểu chính xác những gì xảy ra khác nhau dưới vỏ bọc của chip - từ quan điểm của phần mềm, không có sự khác biệt từ một đồng bằng cũ nop).

Sau khi pause nó kiểm tra lại giá trị - nếu nó lớn hơn 0, khóa không được yêu cầu để nó nhảy lên đầu hàm và cố gắng yêu cầu khóa lại. Nếu không, nó sẽ chuyển sang lại pause.

Sự khác biệt chính giữa spinlock này và phiên bản Boost là điều này không bao giờ làm bất cứ điều gì huyền ảo hơn pause khi quay vòng - không có gì giống như sched_yield() hoặc nanosleep(). Vì vậy, các chủ đề vẫn nóng. Tôi không chắc chắn chính xác làm thế nào điều này đóng trong hai hành vi bạn lưu ý, nhưng mã glibc sẽ được tham lam - nếu một sợi đang quay trên khóa và có các chủ đề khác đã sẵn sàng để chạy nhưng không có lõi có sẵn, sợi kéo sợi doesn ' t giúp các chủ đề chờ đợi nhận được bất kỳ thời gian cpu, trong khi phiên bản Boost cuối cùng sẽ tự nguyện nhường đường cho các chủ đề đó đang chờ đợi một số sự chú ý.

+0

Tôi tìm thấy nó ở đâu đó trực tuyến - tiếc là tôi không thể nhớ chính xác nơi - tôi đã sử dụng pthread_spin_lock trong các bài kiểm tra của mình, tìm ra kết quả tôi đã báo cáo và khi tôi thấy sự khác biệt, hãy tìm mã nguồn để thử hiểu điều gì đang xảy ra , thấy rằng hội đồng, và khi tôi không thể hiểu, đã tìm kiếm sự giúp đỡ ở đây. Cảm ơn bạn đã trả lời và giải thích! –

+0

Tôi tự hỏi Điều này dường như phản trực giác với tôi - việc thực thi pthread tham lam mà không từ bỏ cốt lõi của nó dưới ganh đua thực hiện tốt hơn khi các lõi được đăng ký quá nhiều (nhiều chủ đề hơn lõi) - Tôi đã mong đợi việc thực hiện tăng cường để làm tốt hơn trong kịch bản đó. –

+0

@lori: thật khó để nói điều gì đang xảy ra - chúng tôi không có thông tin về điểm chuẩn. Điều đó nói rằng, tôi không chắc chắn làm thế nào thường xuyên sử dụng spinlocks có ý nghĩa trong mã chế độ người dùng. Ngay cả khi họ đã làm vào những thời điểm, tôi nghĩ rằng họ nên được sử dụng chỉ khi người ta mong đợi sự tranh chấp thấp và rằng họ sẽ được tổ chức trong một thời gian ngắn nhất có thể. Thực hiện các loại kiểm tra mà Boost có thể là một chút của overengineering. Sau đó, một lần nữa, đó là tất cả chỉ là ý kiến ​​dựa trên cảm giác ruột, không phải dữ liệu. –