2013-05-09 41 views
6

Đôi khi, khi tôi chạy chương trình đơn giản nàyTrình lập lịch trình chuỗi Windows không công bằng?

#include <Windows.h> 

DWORD WINAPI ThreadStart(LPVOID) 
{ 
    for (;;) { } 
    return 0; 
} 

int _tmain() 
{ 
    SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); 

    SYSTEM_INFO si; 
    GetSystemInfo(&si); 
    for (DWORD i = si.dwNumberOfProcessors * 2; i > 0; i--) 
    { CloseHandle(CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL)); } 

    Sleep(INFINITE); 
} 

tôi quan sát lịch chủ đề liên tục không công bằng, chẳng hạn như:

Screenshot

Đó không phải là không công bằng trên tất cả chạy, nhưng khi nó , nó vẫn không công bằng trong suốt vòng đời của ứng dụng.

Tại sao điều này xảy ra và cách thích hợp để tránh điều đó là gì?

+0

Bạn có chế độ CPU nào? Nó thực sự là một lõi tứ, hay là lõi kép với siêu phân luồng? – selbie

+0

Ngoài ra, phiên bản Windows nào. Đó cũng là điều quan trọng cần biết. – selbie

+0

@selbie: HT 2 lõi (Core i5, là máy tính xách tay), Windows 8 x64. – Mehrdad

Trả lời

1

Một số tùy chọn:


Nếu (và chỉ nếu) bạn đang chạy Windows 7/8 64-bit (không 32-bit), hoặc Windows Server 2008 R2 hoặc mới hơn, bạn có thể bỏ qua bộ lập lịch hệ thống một cách hoàn toàn và tự chăm sóc nó, mặc dù nó không phải là một công việc tầm thường!

Đó là described on MSDN here và được gọi là Lập lịch chế độ người dùng (UMS).

Ảnh chụp màn hình một phần từ MSDN bên dưới - điều này có sử dụng cho bạn không?

enter image description here

Bên cạnh đó, nó có thể là một ý tưởng vô hiệu hóa Hyper-Threading trong BIOS của bạn (nếu có) vì có một số cuộc tranh luận như thế nào của Windows phân biệt giữa lõi logic và vật lý. See here for a discussion.

Ngoài ra còn có một vài chức năng có sẵn như SetThreadAffinityMask() (MSDN here) và SetThreadIdealProcessor(), điều này có thể giúp mặc dù cá nhân tôi nhận thấy điều này là hơi bị lỗi. Nó thường xuyên hơn trong trường hợp tôi làm tổn thương thông lượng tổng thể hơn là giúp nó.

+0

Tôi thực sự không thể tắt HT vì tùy chọn không có (tôi cũng không muốn ... cũng không hiểu tại sao nó thay đổi bất kỳ thứ gì). Thật không may, thiết lập bộ xử lý ái lực hoặc lý tưởng cũng không thay đổi bất cứ thứ gì. UMS có vẻ hơi ồ ạt và tôi không chắc liệu nó có giúp ích gì cho bạn hay không, ít nhất là nó cũng có thể hoạt động. – Mehrdad

0

Đây là cảnh quay trong phỏng đoán tối.

Nhưng tôi sẽ đề nghị Hyper-Threading có thể làm lệch kết quả một chút.

Nếu bios/cmos của máy tính xách tay của bạn cho phép vô hiệu hoá siêu phân luồng khi một số máy tính thực hiện, thì sẽ rất thú vị khi thấy các số có mã của bạn chỉ chạy trên lõi thực.

Và ngay cả khi HT là lý do tại sao nó thiên vị trên sợi, thì tôi vẫn không biết tại sao nó sẽ làm điều đó.

+0

Không, tôi không thể tắt HT, và như bạn đã đề cập, nó không thực sự giải thích những gì tôi nhận được. – Mehrdad

1

Bạn sẽ thấy điều này trên một hệ thống đa xử lý bất cứ khi nào một chuỗi không phải là một phần của chương trình của bạn chạy. Giả sử có một tác vụ hệ thống khởi động để chạy trong vài giây, quét các hội đồng .NET hoặc một cái gì đó. Nó sẽ gõ một trong các chủ đề của bạn ra khỏi lịch trình cho một số lát thời gian trong khi luồng trên các lõi khác tiếp tục chạy. Chủ đề bị loại ra sẽ không bao giờ bắt kịp với những người khác.

+1

Điều này tiếp tục mãi mãi. Tôi không đếm chu kỳ tuyệt đối, tôi đang đếm nhìn vào việc sử dụng CPU, mà không có gì để làm với lịch sử quá khứ của chủ đề. Ngoài ra, không có nhiệm vụ hệ thống, vv mà gây ra điều này - đây là chương trình duy nhất chạy, khá rõ ràng là dễ dàng để nói từ công việc quản lý hoặc các công cụ như thế. – Mehrdad

0

Trên hệ thống của tôi, SetThreadAffinityMask dường như giảm thiểu vấn đề. Vẫn còn một số sự mất cân bằng, rõ ràng là do một lõi có ít thời gian hơn so với người khác, nhưng nó không nghiêm trọng.

Windows dường như không muốn di chuyển các chủ đề này giữa các lõi; họ hiếm khi thay đổi lõi sau giây đầu tiên.Nếu các luồng không phân bố đều giữa các lõi, thời gian của luồng sẽ phản ánh điều đó.

Đây là mã tôi đã sử dụng để thử mặt nạ ái lực:

#include <Windows.h> 
#include <stdio.h> 

DWORD WINAPI ThreadStart(LPVOID arg) 
{ 
    DWORD pn1, pn2; 

    printf("Thread %u on processor %u\n", GetThreadId(GetCurrentThread()), pn1 = GetCurrentProcessorNumber()); 

    // The problem comes back if you enable this line 
    // SetThreadAffinityMask(GetCurrentThread(), -1); 

    for (;;) 
    { 
     for (int i = 0; i < 10000; i++); 
     pn2 = GetCurrentProcessorNumber(); 
     if (pn2 != pn1) 
     { 
      pn1 = pn2; 
      printf("Thread %u on processor %u\n", GetThreadId(GetCurrentThread()), pn1); 
     } 
    } 
    return 0; 
} 

int main(int argc, char ** argv) 
{ 
    SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); 

    SYSTEM_INFO si; 
    GetSystemInfo(&si); 

    for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) 
    { 
     SetThreadAffinityMask(CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL), 1 << i); 
     SetThreadAffinityMask(CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL), 1 << i); 
    } 

    Sleep(INFINITE); 
    return 0; 
} 

Cách tiếp cận này cũng dường như để giảm thiểu vấn đề này, mặc dù có lẽ không phải là một cách hiệu quả:

#include <Windows.h> 
#include <stdio.h> 

DWORD WINAPI ThreadStart(LPVOID arg) 
{ 
    for (;;); 
    return 0; 
} 

int main(int argc, char ** argv) 
{ 
    SYSTEM_INFO si; 
    GetSystemInfo(&si); 

    for (DWORD i = si.dwNumberOfProcessors * 2; i > 0; i--) 
    { 
     CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL); 
    } 

    for (;;) 
    { 
     SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); 
     Sleep(100); 
     SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); 
    } 

    return 0; 
} 

Tôi nghi ngờ rằng chúng tôi xem xét lại một số biện pháp tiết kiệm năng lượng được thiết kế dựa trên giả định rằng các luồng có mức độ ưu tiên thấp không cần lập lịch biểu công bằng. (Có thể cho rằng, đặt một luồng hoặc quy trình thành mức độ ưu tiên thấp cho biết "Tôi không quan tâm tôi nhận được bao nhiêu CPU.")

Các vấn đề liên quan