2009-03-13 26 views
9

私はしかし、POSIXセマフォのいくつかは、Mac OS Xで実装されていないのMac OS Xにセマフォを使用します(Linuxからの)プロジェクトPOSIXセマフォ:sem_timedwait代替

1つのポートにしようとしています私は、このポートでヒット、私はセマフォについて多くを知っているが、manページsem_wait()からsem_timedwaitに近いと思わないでくださいsem_timedwait()

あり、それはmanページから

を実現している

sem_timedwait()関数は、関数のように、
semによって参照されるセマフォをロックします。 セマフォは別の プロセスを待たずに
ロックするかsem_post() 機能を実行することにより
セマフォのロックを解除するスレッドができない場合は、この待ち時間は、指定されたタイムアウト が

を満了したときにminatedター
しなければなりませんsemphoresがどのように動作するかの私の限られた理解から

私はsem_timedwait()がより安全であることを確認することができますが、私はまだsem_wait()

Iを使用することができるはずですこれは正しい?そうでない場合は、タイマーがあれば有効期限が切れた後、他の選択肢は私が...

おかげで

答えて

6

タイムアウトがアルゴリズムの操作にとって重要である可能性があります。したがって、ちょうどsem_wait()を使用すると動作しない可能性があります。

sem_trywait()を使用すると、すべての場合ですぐに返されます。次に、選択したスリープインターバルをループして使用し、タイムアウトがなくなるか、セマフォが取得されるまで、合計タイムアウトを減らします。

より良い解決策は、条件変数を使用するアルゴリズムを書き直してから、pthread_cond_timedwait()を使用して適切なタイムアウトを取得することです。

+0

睡眠とtrywaitでループをプロセスが毎回キュー内の位置を失うため、動作しません。多くのスレッドまたはプロセスが1つのセマフォをロックしようとすると、ロックされてタイムアウトすると、それらのうちのいくつかが常にヒットします。 ビジーループが機能する可能性がありますが、解決策ではありません。 – Eugene

+0

クロスプロセスで動作する条件変数を使用するには、どのように書き直しますか? – rogerdpack

1

あなたはsem_post(呼び出し、別のスレッドでタイマーを開始することにより()の呼び出し)sem_timedwaitの機能を模倣しようとすることができていないものをsem_post()を呼び出すはずのプライマリスレッドから呼び出されていませんか?

3

あなたはapacheポータブルランタイムの使用を検討しましたか?これは、すべてのMac OS Xボックスと多くのLinuxディストリビューションにプリインストールされており、それもMS Windows上で動作するスレッドの同時実行の周りのプラットフォーム中立のラッパー、付属しています:あなただけのMPのAPIを使用することができる場合

http://apr.apache.org/docs/apr/1.3/group__apr__thread__cond.html

+0

これはクロスプロセス同期のために機能しますか? – rogerdpack

0

  • MPCreateSemaphore/MPDeleteSemaphore
  • MPSignalSemaphore/MPWaitOnSemaphore

シグナリングなしで指定されたタイムアウトを超えた場合、はkMPTimeoutErrで存在します。

+0

残念ながら、MultiProcessing APIは10.7では廃止されました。 – MaddTheSane

1

最も簡単な解決策は、alarm()の呼び出しと組み合わせてsem_wait()を使用して待機を中断させることです。例:

1つの問題は、アラームとして入力する秒数が時間がかかることがあるためです。

- aghiles

2

さらに別の代替は、オーストラリアの天文台のソフトウェアグループのキースShortridgeによってsem_timedwait.c 実装を使用することであってもよいです。ソースファイルから

/* 
*      s e m _ t i m e d w a i t 
* 
* Function: 
*  Implements a version of sem_timedwait(). 
* 
* Description: 
*  Not all systems implement sem_timedwait(), which is a version of 
*  sem_wait() with a timeout. Mac OS X is one example, at least up to 
*  and including version 10.6 (Leopard). If such a function is needed, 
*  this code provides a reasonable implementation, which I think is 
*  compatible with the standard version, although possibly less 
*  efficient. It works by creating a thread that interrupts a normal 
*  sem_wait() call after the specified timeout. 
* 
* ... 
* 
* Limitations: 
* 
*  The mechanism used involves sending a SIGUSR2 signal to the thread 
*  calling sem_timedwait(). The handler for this signal is set to a null 
*  routine which does nothing, and with any flags for the signal 
*  (eg SA_RESTART) cleared. Note that this effective disabling of the 
*  SIGUSR2 signal is a side-effect of using this routine, and means it 
*  may not be a completely transparent plug-in replacement for a 
*  'normal' sig_timedwait() call. Since OS X does not declare the 
*  sem_timedwait() call in its standard include files, the relevant 
*  declaration (shown above in the man pages extract) will probably have 
*  to be added to any code that uses this. 
* 
* ... 
* 
* Copyright (c) Australian Astronomical Observatory. 
* Commercial use requires permission. 
* This code comes with absolutely no warranty of any kind. 
*/ 
+0

リンクは更新が必要です。404 – cbinder

+0

これはhttps://github.com/attie/libxbee3/blob/master/xsys_darwin/sem_timedwait.cです。 –

0

私は代替として、以下の機能を使用して計画されたが、その後、私はその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のセマフォーをネイティブ実装だけであきらめていません)いずれにしても、誰もがセマンティック実装を持っていますので、他の人がパスタを心の中身にコピーすることができます。

0

私はOSX上で名前付きセマフォを使用していましたが、現在はsem_timedwaitは使用できません。また、sem_initとfriendsは推奨されなくなりました。私はpthread mutexと以下のような条件を使ってセマフォーを実装しました(OSX 10.13.1)。あなたはそれがそれにPTRを保持することはできません場合は、構造体のテーブル対ハンドルを作成し、sem_tタイプをルックアップする必要がある場合があります(つまり、ポインタが64-ビットであり、sem_tは32です?)

#ifdef __APPLE__ 

typedef struct 
{ 
    pthread_mutex_t count_lock; 
    pthread_cond_t count_bump; 
    unsigned count; 
} 
bosal_sem_t; 

int sem_init(sem_t *psem, int flags, unsigned count) 
{ 
    bosal_sem_t *pnewsem; 
    int result; 

    pnewsem = (bosal_sem_t *)malloc(sizeof(bosal_sem_t)); 
    if (! pnewsem) 
    { 
     return -1; 
    } 
    result = pthread_mutex_init(&pnewsem->count_lock, NULL); 
    if (result) 
    { 
     free(pnewsem); 
     return result; 
    } 
    result = pthread_cond_init(&pnewsem->count_bump, NULL); 
    if (result) 
    { 
     pthread_mutex_destroy(&pnewsem->count_lock); 
     free(pnewsem); 
     return result; 
    } 
    pnewsem->count = count; 
    *psem = (sem_t)pnewsem; 
    return 0; 
} 

int sem_destroy(sem_t *psem) 
{ 
    bosal_sem_t *poldsem; 

    if (! psem) 
    { 
     return EINVAL; 
    } 
    poldsem = (bosal_sem_t *)*psem; 

    pthread_mutex_destroy(&poldsem->count_lock); 
    pthread_cond_destroy(&poldsem->count_bump); 
    free(poldsem); 
    return 0; 
} 

int sem_post(sem_t *psem) 
{ 
    bosal_sem_t *pxsem; 
    int result, xresult; 

    if (! psem) 
    { 
     return EINVAL; 
    } 
    pxsem = (bosal_sem_t *)*psem; 

    result = pthread_mutex_lock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    pxsem->count = pxsem->count + 1; 

    xresult = pthread_cond_signal(&pxsem->count_bump); 

    result = pthread_mutex_unlock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    if (xresult) 
    { 
     errno = xresult; 
     return -1; 
    } 
} 

int sem_trywait(sem_t *psem) 
{ 
    bosal_sem_t *pxsem; 
    int result, xresult; 

    if (! psem) 
    { 
     return EINVAL; 
    } 
    pxsem = (bosal_sem_t *)*psem; 

    result = pthread_mutex_lock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    xresult = 0; 

    if (pxsem->count > 0) 
    { 
     pxsem->count--; 
    } 
    else 
    { 
     xresult = EAGAIN; 
    } 
    result = pthread_mutex_unlock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    if (xresult) 
    { 
     errno = xresult; 
     return -1; 
    } 
    return 0; 
} 

int sem_wait(sem_t *psem) 
{ 
    bosal_sem_t *pxsem; 
    int result, xresult; 

    if (! psem) 
    { 
     return EINVAL; 
    } 
    pxsem = (bosal_sem_t *)*psem; 

    result = pthread_mutex_lock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    xresult = 0; 

    if (pxsem->count == 0) 
    { 
     xresult = pthread_cond_wait(&pxsem->count_bump, &pxsem->count_lock); 
    } 
    if (! xresult) 
    { 
     if (pxsem->count > 0) 
     { 
      pxsem->count--; 
     } 
    } 
    result = pthread_mutex_unlock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    if (xresult) 
    { 
     errno = xresult; 
     return -1; 
    } 
    return 0; 
} 

int sem_timedwait(sem_t *psem, const struct timespec *abstim) 
{ 
    bosal_sem_t *pxsem; 
    int result, xresult; 

    if (! psem) 
    { 
     return EINVAL; 
    } 
    pxsem = (bosal_sem_t *)*psem; 

    result = pthread_mutex_lock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    xresult = 0; 

    if (pxsem->count == 0) 
    { 
     xresult = pthread_cond_timedwait(&pxsem->count_bump, &pxsem->count_lock, abstim); 
    } 
    if (! xresult) 
    { 
     if (pxsem->count > 0) 
     { 
      pxsem->count--; 
     } 
    } 
    result = pthread_mutex_unlock(&pxsem->count_lock); 
    if (result) 
    { 
     return result; 
    } 
    if (xresult) 
    { 
     errno = xresult; 
     return -1; 
    } 
    return 0; 
} 

#endif