15

セマフォを使用するプロジェクトを (Linux から) Mac OS X に移植しようとしていますが、一部の posix セマフォは Mac OS X に実装されていません。

このポートで打ったのはsem_timedwait()

セマフォについてはよくわかりませんが、マニュアルページからはsem_wait()近いようsem_timedwaitで、実装されています

マニュアルページから

sem_timedwait()
sem関数は、関数内の as によって参照されるセマフォをロックしsem_wait()ます。ただし、別のプロセスまたはスレッドが関数 を実行してセマフォ
をロック解除するのを待たずにセマフォをロックできない場合 、この待機は 、指定されたタイムアウトが期限切れになると終了します。
sem_post()

セムフォがどのように機能するかについての私の限られた理解から、sem_timedwait()より安全であることがわかりますが、それでも sem_wait() を使用できるはずです

これは正しいです?そうでない場合、他にどのような選択肢がありますか...

ありがとう

4

9 に答える 9

7

タイムアウトは、アルゴリズムの動作にとって重要である可能性があります。したがって、使用するだけでは機能しない場合sem_wait()があります。

sem_trywait()すべての場合にすぐに返される を使用できます。その後、ループし、選択したスリープ間隔を使用して、タイムアウトを使い果たすか、セマフォが取得されるまで、合計タイムアウトを減らすたびに使用できます。

はるかに優れた解決策は、条件変数を使用するようにアルゴリズムを書き直すことです。その後pthread_cond_timedwait()、適切なタイムアウトを取得するために使用できます。

于 2009-05-03T07:03:07.427 に答える
3

さらに別の方法 として、オーストラリア天文台のソフトウェア グループの Keith 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.
*/
于 2013-03-01T17:44:19.907 に答える
2

Apache ポータブル ランタイムの使用を検討しましたか? これは、すべての Mac OS X ボックスと多くの Linux ディストリビューションにプリインストールされており、MS Windows でも動作するスレッド同時実行のプラットフォーム ニュートラル ラッパーが付属しています。

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

于 2009-05-03T16:15:16.693 に答える
1

最も簡単な解決策は、sem_wait()をalarm()の呼び出しと組み合わせて使用​​して、ウェイクアップして待機を中止することだと思います。例えば:

alarm(2);
int return_value = sem_wait( &your_semaphore );
if( return_value == EINTR )
   printf( "we have been interrupted by the alarm." );

1つの問題は、アラームが入力として数秒かかるため、時間指定された待機が長すぎる可能性があることです。

-アギレス

于 2011-12-30T05:54:15.350 に答える
0

sem_post() を呼び出すはずのプライマリ スレッドによって呼び出されていない場合、タイマーの期限が切れた後に sem_post() を呼び出す別のスレッドでタイマーを開始することにより、sem_timedwait() 呼び出しの機能を模倣してみてください。

于 2009-05-03T05:58:36.847 に答える
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() 呼び出し用に予約されており、1 秒未満の精度が必要な場合は事実上役に立ちません。

このコードは、最初に 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 のセマフォをあきらめるのではなく、ネイティブ実装だけです。) いずれにせよ、今では誰もが商用制限なしで sem_timedwait() 実装を持っており、他の人は心ゆくまでコピーパスタできます。

于 2016-05-19T13:22:08.147 に答える
0

MP API を使用できる場合:

  • MPCreateSemaphore/MPDeleteSemaphore
  • MPSignalSemaphore/MPWaitOnSemaphore

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

于 2010-03-03T16:08:40.083 に答える