Tôi có một số mã nơi tôi đang sử dụng dispatch_semaphore_t để báo hiệu hoạt động hoàn thành. Khi semaphore là một biến thành viên, nó dường như không hoạt động chính xác. Tôi sẽ hiển thị mã ví dụ mà làm việc và một ví dụ mà dường như không làm việc:dispatch_semaphore_t tái sử dụng - Tôi thiếu gì ở đây?
@implementation someClass
{
dispatch_semaphore_t memberSem;
dispatch_semaphore_t* semPtr;
NSThread* worker;
BOOL taskDone;
}
- (id)init
{
// Set up the worker thread and launch it - not shown here.
memberSem= dispatch_semaphore_create(0);
semPtr= NULL;
taskDone= FALSE;
}
- (void)dealloc
{
// Clean up the worker thread as needed - not shown here.
if((NULL != semPtr) && (NULL != *semPtr))
disptatch_release(*semPtr);
dispatch_release(memberSem);
}
- (void)doSomethingArduous
{
while([self notDone]) // Does something like check a limit.
[self doIt]; // Does something like process data and increment a counter.
taskDone= TRUE; // I know this should be protected, but keeping the example simple for now.
if((NULL != semPtr) && (NULL != *semPtr))
dispatch_semaphore_signal(*semPtr); // I will put a breakpoint here, call it "SIGNAL"
}
- (BOOL)getSomethingDoneUseLocalSemaphore
{
taskDone= FALSE; // I know this should be protected, but keeping the example simple for now.
dispatch_semaphore_t localSem= dispatch_semaphore_create(0);
semPtr= &localSem;
[self performSelector:doSomethingArduous onThread:worker withObject:nil waitUntilDone:NO];
dispatch_time_t timeUp= dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(2.5 * NSEC_PER_SEC));
dispatch_semaphore_wait(localSem, timeUp);
semPtr= NULL;
dispatch_release(localSem);
// I know I could just return taskDone. The example is this way to show what the problem is.
if(taskDone) // Again with thread safety.
return TRUE;
return FALSE;
}
- (BOOL)getSomethingDoneUseMemberSemaphore
{
taskDone= FALSE; // I know this should be protected, but keeping the example simple for now.
semPtr= &memberSem; // I will put a breakpoint here, call it "START"
[self performSelector:doSomethingArduous onThread:worker withObject:nil waitUntilDone:NO];
dispatch_time_t timeUp= dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(2.5 * NSEC_PER_SEC));
dispatch_semaphore_wait(memberSem, timeUp);
semPtr= NULL;
// I know I could just return taskDone. The example is this way to show what the problem is.
if(taskDone) // Again with thread safety.
return TRUE; // I will put a breakpoint here, call it "TASK_DONE"
return FALSE; // I will put a breakpoint here, call it "TASK_NOT_DONE"
}
- (void)hereIsWhereWeBringItTogether
{
BOOL gotItDoneLocal= [self getSomethingDoneUseLocalSemaphore]; // Will return TRUE.
gotItDoneLocal= [self getSomethingDoneUseLocalSemaphore]; // Will return TRUE.
gotItDoneLocal= [self getSomethingDoneUseLocalSemaphore]; // Will return TRUE.
BOOL gotItDoneMember= [self getSomethingDoneUseMemberSemaphore]; // Will return TRUE. I will put a breakpoint here, call it "RUN_TEST"
gotItDoneMember= [self getSomethingDoneUseMemberSemaphore]; // Will return FALSE.
}
Vì vậy, cho rằng mã và kết quả tôi nhận được/nhận được, tôi đặt breakpoint như mô tả trong mã thực của tôi: Một trong chức năng chính, một để bắt đầu trong chức năng làm việc, một trong những nơi semaphore thành viên được báo hiệu, và hai sau khi chờ đợi.
Những gì tôi thấy là trong trường hợp tôi sử dụng semaphore thành viên, trong vòng đầu tiên tôi dừng lại tại điểm dừng "RUN_TEST", chạy và nhấn breakpoint "START", chạy rồi nhấn breakpoint "SIGNAL", chạy rồi nhấn breakpoint "TASK_DONE" - tất cả như mong đợi.
Khi tôi tiếp tục chạy, tôi nhấn breakpoint "START", chạy sau đó nhấn breakpoint "TASK_NOT_DONE", chạy sau đó nhấn breakpoint "TÍN HIỆU"
Đó là, khi tôi chạy trình tự sử dụng một semaphore đó là một thành viên, và làm những gì trông giống như tín hiệu thích hợp/chờ đợi, lần thứ hai tôi cố gắng chờ đợi semaphore đó tôi dường như thổi bởi và nó được báo hiệu sau khi tôi đã thoát khỏi chờ đợi.
Tôi có vẻ không quản lý quyền đếm (tín hiệu/cặp đôi chờ đợi) hoặc semaphore thành viên đó sẽ không quay trở lại trạng thái chưa được báo hiệu.
Cảm giác của tôi là có điều gì đó cơ bản mà tôi thiếu ở đây. Mội thông tin đầu vào đều sẽ được xem xét kĩ.
EDIT: Cuối cùng, những gì tôi dường như bị thiếu là do mã thực sự của tôi phức tạp hơn một chút. Thay vì một sự trở lại sạch từ nhiệm vụ khó khăn, có nhiều chủ đề liên quan và một postNotification. Tôi đã thay thế postNotification bằng mã trong trình xử lý thông báo - nó đặt cờ và báo hiệu semaphore. Bằng cách đó, bất kỳ sự chậm trễ nào có thể đã được giới thiệu bởi trình xử lý thông báo đều bị loại bỏ.
Tôi hiểu ý của bạn là gì. Về cơ bản, nếu tác vụ mất nhiều thời gian hơn chờ đợi, thời gian chờ sẽ hết thời gian chờ, nhưng tín hiệu sẽ vẫn tăng bộ đếm, vì vậy lần chờ tiếp theo sẽ kích hoạt ngay lập tức. Đó là một cái gì đó tôi nghĩ về, nhưng trong trường hợp này tôi có thể treo lên một máy phân tích và thấy rằng hành động hoàn thành trong thời gian phụ thứ hai. Tôi đoán tôi có thể kiểm tra xem semaphore được báo hiệu lần thứ hai bằng cách chỉ cần chờ đợi * trước * tôi bắt đầu quá trình dài của tôi. Nếu nó không hết thời gian chờ, tôi biết những gì đang diễn ra và có thể điều chỉnh thời gian chờ của tôi một cách thích hợp. – GTAE86
@ GTAE86 Chính xác. BTW, cách bạn đã thiết lập mã semaphore địa phương của mình, bạn có thể, về mặt lý thuyết vẫn thấy hành vi tương tự như ví dụ biến thành viên của bạn (nó hoàn toàn là vấn đề thời gian chính xác). Nếu bạn hoàn toàn không muốn giao tiếp giữa các tín hiệu khác nhau của các nhiệm vụ khác nhau, thay vì chọn lên semaphore từ một số biến mẫu (ngay cả ví dụ "biến cục bộ" hiện tại của bạn sẽ lưu trữ semaphore trong một biến mẫu), bạn muốn để vượt qua semaphore như một tham số, không sử dụng một biến cá thể (hoặc tạo một cá thể riêng biệt của đối tượng của bạn cho mỗi hoạt động). – Rob
Tôi nghĩ rằng tôi * có thể * xem điều gì đang xảy ra trong mã của tôi. Nhiều chủ đề đang được chơi (cách phức tạp hơn ví dụ).Quá trình gian truân là: Trong chủ đề Một chuỗi cuộc gọi B để ghi vào một thiết bị, đợi. Chủ đề C được đáp ứng (ReadPipeAsync), lưu trữ nó trong một deque. Chủ đề D bỏ nó ra để phân tích. Nếu tốt, nó sẽ gửi thông báo với kết quả. Trình xử lý thông báo thực hiện một số kiểm tra, đặt trạng thái hoàn thành (thành một biến khóa được bảo vệ) và báo hiệu semaphore nếu được yêu cầu. Mặc dù tôi biết hoạt động của mình đã hoàn tất nhanh chóng, thông báo đó có thể bị trì hoãn. – GTAE86