Sự tách biệt giữa các chuỗi hệ thống được quản lý và vận hành có ngày trở lại .Net 2.0 và kế hoạch của nhóm SQL Server để triển khai các luồng Net sử dụng các sợi. Điều này không bao giờ thực sự đi đâu cả, vì vậy trong khi không có gì đảm bảo rằng một luồng được quản lý sẽ luôn chạy trên cùng một luồng hệ điều hành, trong thực tế, đây luôn là trường hợp cho tất cả các máy chủ .Net hiện tại. Cho rằng điều này đã không thay đổi trong tất cả các năm kể từ khi giới thiệu .Net 2.0, nó không chắc điều này sẽ bao giờ thay đổi.
Có thể tăng cường sự tự tin của chúng tôi ngay cả đối với các phiên bản tương lai của. Net bằng cách sử dụng phương thức System.Threading.Thread.BeginThreadAffinity
. Điều này đảm bảo rằng luồng được quản lý sẽ nằm trên cùng một luồng hệ điều hành (vì vậy nó không có gì trên máy chủ CLR mặc định, vì nó đã đúng theo mặc định). Tôi cho rằng nó vẫn có thể là các luồng quản lý khác có thể chia sẻ cùng một luồng hệ điều hành, nhưng điều này dường như không chắc chắn và chắc chắn không phải là trường hợp trong bất kỳ máy chủ .Net hiện tại nào.
.Net cung cấp khả năng truy cập các chuỗi hệ điều hành gốc sử dụng lớp System.Diagnostics.ProcessThread
và lớp này có khả năng thay đổi ái lực bộ xử lý của chuỗi bằng cách sử dụng thuộc tính ProcessorAffinity
. Tuy nhiên, việc liên kết một chuỗi được quản lý cụ thể với số ProcessThread
của chúng tôi đã được thực hiện một cách có chủ ý.
Cách thực sự duy nhất để thực hiện điều đó là từ bên trong chính chuỗi đó. Sử dụng phương thức System.AppDomain.GetCurrentThreadId
(hoặc PInvoke chức năng GetCurrentThreadId
nếu bạn không muốn gọi phương thức không dùng nữa, mặc dù điều đó sẽ không hoạt động với Mono trên các hệ điều hành khác ngoài Windows). Điều này sau đó có thể được kết hợp với thuộc tính ProcessThread.Id
.
này làm cho nó có thể thiết lập mối quan hệ bộ vi xử lý của chủ đề với đoạn mã sau (được gọi từ bên thread):
/// <summary>
/// Sets the processor affinity of the current thread.
/// </summary>
/// <param name="cpus">A list of CPU numbers. The values should be
/// between 0 and <see cref="Environment.ProcessorCount"/>.</param>
public static void SetThreadProcessorAffinity(params int[] cpus)
{
if(cpus == null)
throw new ArgumentNullException("cpus");
if(cpus.Length == 0)
throw new ArgumentException("You must specify at least one CPU.", "cpus");
// Supports up to 64 processors
long cpuMask = 0;
foreach(int cpu in cpus)
{
if(cpu < 0 || cpu >= Environment.ProcessorCount)
throw new ArgumentException("Invalid CPU number.");
cpuMask |= 1L << cpu;
}
// Ensure managed thread is linked to OS thread; does nothing on default host in current .Net versions
Thread.BeginThreadAffinity();
#pragma warning disable 618
// The call to BeginThreadAffinity guarantees stable results for GetCurrentThreadId,
// so we ignore the obsolete warning
int osThreadId = AppDomain.GetCurrentThreadId();
#pragma warning restore 618
// Find the ProcessThread for this thread.
ProcessThread thread = Process.GetCurrentProcess().Threads.Cast<ProcessThread>()
.Where(t => t.Id == osThreadId).Single();
// Set the thread's processor affinity
thread.ProcessorAffinity = new IntPtr(cpuMask);
}
Hãy ghi nhớ rằng trong khi làm việc này trên các phiên bản hiện tại của Net, về mặt lý thuyết việc thiếu bảo đảm rằng các luồng được quản lý bị ràng buộc với các luồng hệ điều hành có thể phá vỡ mã này trong tương lai. Tuy nhiên, tôi cho rằng điều này rất khó xảy ra.