Tôi đã lên kế hoạch về việc sử dụng các chức năng sau đây như một sự thay thế nhưng sau đó tôi phát hiện ra rằng sem_getvalue() cũng được tán thành và không có chức năng trên OSX. Bạn được tự do sử dụng mã không được kiểm tra dưới đây theo giấy phép MIT hoặc LGPL (lựa chọn của bạn).
#ifdef __APPLE__
struct CSGX__sem_timedwait_Info
{
pthread_mutex_t MxMutex;
pthread_cond_t MxCondition;
pthread_t MxParent;
struct timespec MxTimeout;
bool MxSignaled;
};
void *CSGX__sem_timedwait_Child(void *MainPtr)
{
CSGX__sem_timedwait_Info *TempInfo = (CSGX__sem_timedwait_Info *)MainPtr;
pthread_mutex_lock(&TempInfo->MxMutex);
// Wait until the timeout or the condition is signaled, whichever comes first.
int Result;
do
{
Result = pthread_cond_timedwait(&TempInfo->MxCondition, &TempInfo->MxMutex, &TempInfo->MxTimeout);
if (!Result) break;
} while (1);
if (errno == ETIMEDOUT && !TempInfo->MxSignaled)
{
TempInfo->MxSignaled = true;
pthread_kill(TempInfo->MxParent, SIGALRM);
}
pthread_mutex_unlock(&TempInfo->MxMutex);
return NULL;
}
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
{
// Quick test to see if a lock can be immediately obtained.
int Result;
do
{
Result = sem_trywait(sem);
if (!Result) return 0;
} while (Result < 0 && errno == EINTR);
// Since it couldn't be obtained immediately, it is time to shuttle the request off to a thread.
// Depending on the timeout, this could take longer than the timeout.
CSGX__sem_timedwait_Info TempInfo;
pthread_mutex_init(&TempInfo.MxMutex, NULL);
pthread_cond_init(&TempInfo.MxCondition, NULL);
TempInfo.MxParent = pthread_self();
TempInfo.MxTimeout.tv_sec = abs_timeout->tv_sec;
TempInfo.MxTimeout.tv_nsec = abs_timeout->tv_nsec;
TempInfo.MxSignaled = false;
sighandler_t OldSigHandler = signal(SIGALRM, SIG_DFL);
pthread_t ChildThread;
pthread_create(&ChildThread, NULL, CSGX__sem_timedwait_Child, &TempInfo);
// Wait for the semaphore, the timeout to expire, or an unexpected error condition.
do
{
Result = sem_wait(sem);
if (Result == 0 || TempInfo.MxSignaled || (Result < 0 && errno != EINTR)) break;
} while (1);
// Terminate the thread (if it is still running).
TempInfo.MxSignaled = true;
int LastError = errno;
pthread_mutex_lock(&TempInfo.MxMutex);
pthread_cond_signal(&TempInfo.MxCondition);
pthread_mutex_unlock(&TempInfo.MxMutex);
pthread_join(ChildThread, NULL);
pthread_cond_destroy(&TempInfo.MxCondition);
pthread_mutex_destroy(&TempInfo.MxMutex);
// Restore previous signal handler.
signal(SIGALRM, OldSigHandler);
errno = LastError;
return Result;
}
#endif
SIGALRM có ý nghĩa hơn so với SIGUSR2 như một ví dụ khác ở đây rõ ràng là sử dụng (Tôi không bận tâm khi nhìn vào nó). SIGALRM chủ yếu dành cho các cuộc gọi báo động(), hầu như vô dụng khi bạn muốn độ phân giải phụ.
Mã này đầu tiên cố gắng để có được semaphore với sem_trywait(). Nếu điều đó ngay lập tức thành công, thì nó sẽ thoát ra. Nếu không, nó bắt đầu một luồng là nơi bộ đếm thời gian được thực hiện thông qua pthread_cond_timedwait(). Boolean MxSignaled được sử dụng để xác định trạng thái timeout.
Bạn cũng có thể tìm thấy chức năng này có liên quan hữu ích cho gọi trên sem_timedwait() thực hiện (một lần nữa, MIT hay LGPL, sự lựa chọn của bạn):
int CSGX__ClockGetTimeRealtime(struct timespec *ts)
{
#ifdef __APPLE__
clock_serv_t cclock;
mach_timespec_t mts;
if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock) != KERN_SUCCESS) return -1;
if (clock_get_time(cclock, &mts) != KERN_SUCCESS) return -1;
if (mach_port_deallocate(mach_task_self(), cclock) != KERN_SUCCESS) return -1;
ts->tv_sec = mts.tv_sec;
ts->tv_nsec = mts.tv_nsec;
return 0;
#else
return clock_gettime(CLOCK_REALTIME, ts);
#endif
}
Giúp cư một cấu trúc TIMESPEC với điều gần gũi nhất với những gì clock_gettime() có thể cung cấp. Có nhiều ý kiến khác nhau về việc gọi host_get_clock_service() liên tục là tốn kém. Nhưng bắt đầu một sợi cũng đắt tiền.
Sửa lỗi thực sự là để Apple thực hiện toàn bộ đặc điểm POSIX, không chỉ các phần bắt buộc. Chỉ thực hiện các bit bắt buộc của POSIX và sau đó yêu cầu tuân thủ POSIX chỉ để lại cho mọi người một hệ điều hành bị hỏng một nửa và nhiều cách giải quyết như trên có thể có hiệu suất ít hơn lý tưởng.
Ở trên tất cả đã nói, tôi đang từ bỏ các ẩn dụ bản địa (cả Sys V và POSIX) trên cả Mac OSX và Linux. Chúng bị phá vỡ theo một vài cách khá đáng tiếc.Mọi người khác cũng nên từ bỏ chúng. Ở mức độ nào, bây giờ tất cả mọi người có một sem_timedwait() thực hiện mà không có hạn chế thương mại mà những người khác có thể sao chép-mì ống để nội dung trái tim của họ.
Vòng lặp với trywait với một giấc ngủ sẽ không hoạt động vì một quá trình sẽ mất vị trí của nó trong hàng đợi mỗi lần. Nếu rất nhiều chủ đề hoặc quá trình đang cố gắng khóa một semaphore một số trong số họ sẽ luôn luôn nhấn nó khi nó bị khóa và do đó timeout. Vòng lặp bận có thể hoạt động nhưng không phải là giải pháp. – Eugene
Làm thế nào để bạn viết lại nó để sử dụng một biến điều kiện làm việc quá trình chéo, bất cứ ai? – rogerdpack