إشارات POSIX على نظام التشغيل Mac OS X:بديل sem_timedwait

StackOverflow https://stackoverflow.com/questions/641126

  •  22-07-2019
  •  | 
  •  

سؤال

أحاول نقل مشروع (من Linux) يستخدم الإشارات إلى نظام التشغيل Mac OS X ولكن بعض إشارات الوضعية لا يتم تنفيذها على نظام التشغيل Mac OS X

الذي ضربته في هذا المنفذ هو sem_timedwait()

لا أعرف الكثير عن الإشارات ولكن من صفحات الرجل sem_wait() يبدو أن تكون قريبة من sem_timedwait ويتم تنفيذه

من صفحات الرجل

sem_timedwait() يجب أن تغلق الوظيفة الإشارة المشار إليها
sem كما في sem_wait() وظيفة.ومع ذلك، إذا كانت الإشارة لا يمكن أن تكون
مغلق دون انتظار عملية أخرى أو مؤشر ترابط لإلغاء قفل
إشارة عن طريق إجراء أ sem_post()الوظيفة، يجب أن يكون هذا الانتظار ثالثًا
مصلحة عندما تنتهي المهلة المحددة

من خلال فهمي المحدود لكيفية عمل السيمفورات أستطيع أن أرى ذلك sem_timedwait() أكثر أمانًا، ولكن لا يزال يتعين علي استخدام sem_wait()

هل هذا صحيح؟إذا لم يكن الأمر كذلك فما هي البدائل الأخرى المتاحة لي ...

شكرًا

هل كانت مفيدة؟

المحلول

ومن المرجح أن مهلة مهمة لتشغيل الخوارزمية. لذلك فقط باستخدام sem_wait() قد لا تعمل.

هل يمكن استخدام sem_trywait()، والتي ترجع على الفور في جميع الحالات. يمكنك ثم حلقة، واستخدام فترة النوم التي تختارها، في كل مرة decrementing مهلة الإجمالية حتى إما نفدت المهلة أو يتم الحصول على إشارة.

وهناك حل أفضل من ذلك بكثير هو إعادة كتابة الخوارزمية لاستخدام متغير حالة، وبعد ذلك يمكنك استخدام pthread_cond_timedwait() للحصول على مهلة مناسبة.

نصائح أخرى

هل تعتبر باستخدام وقت التشغيل المحمولة اباتشي؟ هو المثبتة مسبقا على كل ماك OS X مربع والعديد من توزيعات لينكس وأنه يأتي مع منصة المجمع محايد حول التزامن موضوع، الذي يعمل حتى على ويندوز من مايكروسوفت:

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

بديل آخر قد يكون استخدام 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.
*/

هل يمكنك محاولة لتقليد وظيفة الدعوة sem_timedwait () قبل بدء الموقت في موضوع آخر يدعو sem_post () بعد انتهاء الموقت إذا لم يطلق عليه من قبل موضوع الأساسي الذي من المفترض أن استدعاء sem_post ( )؟

وأعتقد أن أبسط الحلول هو استخدام sem_wait () في توليفة مع الدعوة إلى إنذار () أن يستيقظ إحباط الانتظار. على سبيل المثال:

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

وقضية واحدة هي أن الإنذار يأخذ ثواني كمدخل لذلك الانتظار موقوتة قد تكون طويلة جدا في حالتك.

و- aghiles

واعتدت على استخدام الإشارات اسمه على OSX، ولكن الآن sem_timedwait غير متوفر وsem_init وإهمال الأصدقاء. I نفذت الإشارات باستخدام مزامنة والشروط pthread كما يلي الذي عمل بالنسبة لي (OSX 10.13.1). قد يكون لديك لجعل مؤشر مقابل الجدول البنية والبحث عن نوع sem_t إذا كان لا يمكن عقد PTR في ذلك (أي مؤشرات هي 64bits و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

إذا كان بإمكانك فقط استخدام MP API:

  • MPCreateSemaphore/MPDeleteSemaphore
  • MPSignalSemaphore/MPWaitOnSemaphore

MPWaitOnSemaphore موجود مع kMPTimeoutErr إذا تم تجاوز المهلة المحددة دون الإشارة.

وكنت تخطط لاستخدام الدالة التالية كبديل ولكن بعد ذلك اكتشفت أن 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 معظمها للقلق () ويدعو، والتي هي عديمة الفائدة تقريبا عندما تريد قرار الفرعية الثانية.

وهذا الرمز المحاولات الأولى للحصول على إشارة مع 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
}

ويساعد على تعبئة بنية timespec مع أقرب ما يكون إلى ما clock_gettime () يمكن أن تقدم. هناك تعليقات مختلفة الى ان هناك داعيا host_get_clock_service () بشكل متكرر مكلفة. ولكن بدء الموضوع هو أيضا مكلفة.

والإصلاح الحقيقي هو لشركة آبل لتنفيذ مواصفات POSIX بأكملها، وليس مجرد أجزاء إلزامية. تنفيذ فقط البتات الإلزامية POSIX ثم يدعي الالتزام POSIX يترك فقط الجميع مع نظام التشغيل وطنا نصف كسر من الحلول مثل ما ورد أعلاه التي قد تكون أقل من مثالية الأداء.

ما سبق وقال كل شيء، وأنا التخلي عن الإشارات الأم (سواء للانظمة V وPOSIX) على كل من ماك OSX و Linux. تم كسر فيها في عدد غير قليل من الطرق المؤسفة إلى حد ما. الجميع يجب أن تتخلى عن لهم أيضا. (أنا لا التخلي عن الإشارات على تلك أنظمة تشغيل، فقط تطبيقات الأم). وعلى أية حال، الآن كل شخص لديه تنفيذ sem_timedwait () دون قيود التجارية التي يمكن للآخرين نسخ-المعكرونة لمحتوى قلوبهم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top