Tôi là một nhà phát triển cơ sở đang viết một bản cập nhật cho phần mềm nhận dữ liệu từ giải pháp của bên thứ ba, lưu trữ nó trong cơ sở dữ liệu và sau đó điều kiện dữ liệu được sử dụng bởi một giải pháp bên thứ ba khác. Phần mềm của chúng tôi chạy như một dịch vụ Windows.
Nhìn vào mã từ một phiên bản trước, tôi thấy điều này:
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach(int SomeObject in ListOfObjects)
{
lock (_workerLocker)
{
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
}
// check to see if the service has been stopped. If yes, then exit
if (this.IsRunning() == false)
{
break;
}
lock (_workerLocker)
{
_runningWorkers++;
}
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
Logic có vẻ rõ ràng: Đợi phòng trong nhóm luồng, đảm bảo dịch vụ chưa bị dừng, sau đó tăng bộ đếm luồng và xếp hàng công việc. _runningWorkers
được giảm xuống bên SomeMethod()
trong một lock
tuyên bố mà sau đó gọi Monitor.Pulse(_workerLocker)
.
Câu hỏi của tôi là:
Có bất kỳ lợi ích nào trong việc nhóm tất cả các mã trong một lock
, như thế này:
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach (int SomeObject in ListOfObjects)
{
// Is doing all the work inside a single lock better?
lock (_workerLocker)
{
// wait for room in ThreadPool
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
// check to see if the service has been stopped.
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
_runningWorkers++;
}
else
{
break;
}
}
}
Có vẻ như, nó có thể gây ra thêm một chút chờ đợi cho các luồng khác, nhưng sau đó có vẻ như việc khóa liên tục trong một khối logic duy nhất cũng sẽ hơi tốn thời gian. Tuy nhiên, tôi chưa quen với đa luồng, vì vậy tôi cho rằng có những mối quan tâm khác ở đây mà tôi không biết.
Chỉ có những nơi khác _workerLocker
bị khóa SomeMethod()
và chỉ nhằm mục đích giảm dần _runningWorkers
, sau đó ở ngoài foreach
để chờ số lượng _runningWorkers
chuyển về 0 trước khi đăng nhập và quay trở lại.
Cảm ơn vì bất kì sự giúp đỡ.
EDIT 4/8/15
Cảm ơn @delnan về khuyến nghị sử dụng semaphore. Mã trở thành:
static int MaxSimultaneousThreads = 5;
static Semaphore WorkerSem = new Semaphore(MaxSimultaneousThreads, MaxSimultaneousThreads);
foreach (int SomeObject in ListOfObjects)
{
// wait for an available thread
WorkerSem.WaitOne();
// check if the service has stopped
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
else
{
break;
}
}
WorkerSem.Release()
được gọi là bên trong SomeMethod()
.
SomeMethod
không đồng bộ, phần "khóa" ở trên sẽ được để lại trước hoặc ít nhất là ngay sau khi luồng mới SomeMethod
bắt đầu chạy.
Monitor.Wait()
việc phát hành và mua lại khóa để một tài nguyên khác ( SomeMethod
trong trường hợp này) có thể sử dụng nó. Ở đầu bên kia, SomeMethod
lấy khóa, giảm bộ đếm và sau đó gọi Monitor.Pulse()
các khóa trả về khóa cho phương thức đang đề cập. Một lần nữa, đây là sự hiểu biết của riêng tôi.
Monitor.Wait
phát hành khóa. Tôi khuyên bạn nên có một cái nhìn vào các tài liệu.