私は代替として、以下の機能を使用して計画されたが、その後、私はそのsem_getvalue()はまた、非推奨とOSX上の非機能して発見しました。あなたはMITまたはLGPLライセンス(あなたの選択)の下で次のわずかにテストされていないコードを自由に使用することができます。
#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は明らかに(私はそれを見て気にしませんでした)を使用して、ここで別の例としてSIGUSR2よりも多くの意味があります。 SIGALRMはalarm()呼び出しのためにほとんど予約されています。これは秒未満の分解能が必要な場合には実質的に役に立たない。
このコードは、最初にsem_trywait()でセマフォを取得しようとします。それがすぐに成功すれば、それは崩壊する。さもなければ、それはpthread_cond_timedwait()によってタイマーが実装されているスレッドを開始します。 MxSignaledブール値は、タイムアウト状態を決定するために使用されます。
また、上記sem_timedwait()の実装(再び、MITまたはLGPL、あなたの選択)を呼び出すため、この関連する機能が役立つことがあります。
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
}
は何にclock_gettimeに最も近いものとtimespec構造体を埋めるのに役立ちます() 提供することができます。そこには、host_get_clock_service()を繰り返し呼び出すことが高価であるというさまざまなコメントがあります。しかし、スレッドを起動することも高価です。
実際の修正は、Appleが必須の部分だけでなく、POSIX仕様全体を実装することです。 POSIXの必須ビットを実装してPOSIX準拠を主張するだけで、すべての人に半分の壊れたOSと上記のような回避策があります。
上記はすべて、私はMac OSXとLinuxの両方でネイティブセマフォー(Sys VとPOSIXの両方)をあきらめています。彼らはかなり不幸な方法でかなり壊れています。誰もが彼らをあきらめるべきだ。 (私はそれらのOSのセマフォーをネイティブ実装だけであきらめていません)いずれにしても、誰もがセマンティック実装を持っていますので、他の人がパスタを心の中身にコピーすることができます。
睡眠とtrywaitでループをプロセスが毎回キュー内の位置を失うため、動作しません。多くのスレッドまたはプロセスが1つのセマフォをロックしようとすると、ロックされてタイムアウトすると、それらのうちのいくつかが常にヒットします。 ビジーループが機能する可能性がありますが、解決策ではありません。 – Eugene
クロスプロセスで動作する条件変数を使用するには、どのように書き直しますか? – rogerdpack