2009-03-13 39 views
9

Tôi cố gắng để cổng một dự án (từ linux) có sử dụng Semaphores với máy Mac OS X tuy nhiên một số các Cột posix không được thực hiện trên Mac OS XPOSIX Semaphores trên Mac OS X: sem_timedwait thay thế

Một trong đó tôi đánh vào cổng này là sem_timedwait()

tôi không biết nhiều về semaphores nhưng từ các trang man sem_wait() có vẻ là gần sem_timedwait và nó được thực hiện

từ trang người đàn ông

sem_timedwait() chức năng sẽ khóa semaphore được tham chiếu bởi
sem như trong chức năng sem_wait(). Tuy nhiên, nếu semaphore không thể
khóa mà không cần chờ cho quá trình khác hoặc thread để mở khóa semaphore
bằng cách thực hiện một chức năng sem_post() , chờ đợi này sẽ ter-
minated khi thời gian chờ quy định hết hạn

Từ sự hiểu biết hạn chế của tôi về cách semphores làm việc tôi có thể thấy rằng sem_timedwait() là an toàn hơn, nhưng tôi vẫn sẽ có thể sử dụng sem_wait()

tôi Điều này đúng không? Nếu không gì thay thế khác nào ...

Cảm ơn

Trả lời

6

Đó là khả năng là thời gian chờ là quan trọng đối với hoạt động của thuật toán. Do đó chỉ cần sử dụng sem_wait() có thể không hoạt động.

Bạn có thể sử dụng sem_trywait(), mà trả về ngay lập tức trong mọi trường hợp. Sau đó bạn có thể lặp lại và sử dụng khoảng thời gian ngủ mà bạn chọn, mỗi lần giảm tổng thời gian chờ cho đến khi bạn hết thời gian chờ hoặc bán được.

Một giải pháp tốt hơn là viết lại thuật toán để sử dụng biến điều kiện và sau đó bạn có thể sử dụng pthread_cond_timedwait() để có thời gian chờ phù hợp.

+0

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

+0

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

1

Bạn có thể thử để bắt chước các chức năng của sem_timedwait() gọi bằng cách bắt đầu một bộ đếm thời gian trong một chủ đề mà các cuộc gọi sem_post() sau khi bộ đếm thời gian hết hạn nếu nó chưa được gọi bởi thread chính được gọi là sem_post()?

3

Bạn đã cân nhắc sử dụng thời gian chạy di động apache chưa?Nó được cài đặt sẵn trên mọi máy Mac OS X Box và nhiều distro Linux và nó đi kèm với một wrapper nền tảng trung lập xung quanh chủ đề đồng thời, làm việc ngay cả trên MS Windows:

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

+0

Làm công việc này để đồng bộ hóa quá trình chéo? – rogerdpack

0

Nếu bạn chỉ có thể sử dụng MP API:

  • MPCreateSemaphore/MPDeleteSemaphore
  • MPSignalSemaphore/MPWaitOnSemaphore

MPWaitOnSemaphore tồn tại với kMPTimeoutErr nếu thời gian chờ được chỉ định bị vượt quá mà không báo hiệu.

+0

Thật không may, API đa xử lý đã không được chấp nhận trong 10.7. Liên kết – MaddTheSane

1

Tôi nghĩ giải pháp đơn giản nhất là sử dụng lệnh sem_wait() kết hợp với lệnh gọi báo thức() để đánh thức hủy bỏ việc chờ. Ví dụ:

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

Một vấn đề là báo thức mất vài giây làm đầu vào để thời gian chờ có thể quá dài trong trường hợp của bạn.

- aghiles

2

Tuy nhiên, thay thế khác có thể được sử dụng thực hiện sem_timedwait.c bởi Keith Shortridge của nhóm phần mềm Đài quan sát thiên văn của Úc.

Từ các tập tin nguồn:

/* 
*      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

cần cập nhật, hiển thị 404 – cbinder

+0

Hiện tại, tại https://github.com/attie/libxbee3/blob/master/xsys_darwin/sem_timedwait.c –

0

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ọ.

0

Tôi đã từng sử dụng các semaphores có tên trên OSX, nhưng giờ sem_timedwait không khả dụng và sem_init và bạn bè không được dùng nữa. Tôi đã triển khai semaphores bằng cách sử dụng mutex pthread và các điều kiện như sau mà làm việc cho tôi (OSX 10.13.1). Bạn có thể phải thực hiện một bảng xử lý vs struct và tìm kiếm kiểu sem_t nếu nó không thể giữ một ptr trong nó (tức là con trỏ là 64bits và sem_t là 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