sem_wait的范例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sem_wait的范例相关的知识,希望对你有一定的参考价值。

参考技术A

//(有些琐碎的)程序以下展示了在一个未命名的信号量上的操作.程序请求2个命令行参数,  //第一个参数指定一个秒的参数来作为报警的定时器来产生SIGALRM信号.  //信号处理程序执行sem_post(3)来增加在main()函数中使用sem_wait()等待的信号量的值.  //第二个命令行参数指定超时的长度,为sem_timedwait()使用秒为单位.  //以下展示了程序的执行的不同效果.
$ ./a.out 2 3  About to call sem_timedwait()  sem_post() from handler  sem_getvalue() from handler; value = 1  sem_timedwait() succeeded  $ ./a.out 2 1  About to call sem_timedwait()  sem_timedwait() timed out  Program source  #include <unistd.h>  #include <stdio.h>  #include <stdlib.h>  #include <semaphore.h>  #include <time.h>  #include <assert.h>  #include <errno.h>  #include <signal.h>  sem_t sem;  #define handle_error(msg) /  do

perror(msg);
exit(EXIT_FAILURE);
while (0)  static void  handler(int sig)    write(STDOUT_FILENO, sem_post() from handler/n, 24);  if (sem_post(&sem) == -1)     write(STDERR_FILENO, sem_post() failed/n, 18);  _exit(EXIT_FAILURE);      int  main(int argc, char *argv[])    struct sigaction sa;  struct timespec ts;  int s;  if (argc != 3)     fprintf(stderr, Usage: %s /n,  argv[0]);  exit(EXIT_FAILURE);    if (sem_init(&sem, 0, 0) == -1)  handle_error(sem_init);  /* Establish SIGALRM handler; set alarm timer using argv[1] */  sa.sa_handler = handler;  sigemptyset(&sa.sa_mask);  sa.sa_flags = 0;  if (sigaction(SIGALRM, &sa, NULL) == -1)  handle_error(sigaction);  alarm(atoi(argv[1]));  /* Calculate relative interval as current time plus  number of seconds given argv[2] */  if (clock_gettime(CLOCK_REALTIME, &ts) == -1)  handle_error(clock_gettime);  ts.tv_sec += atoi(argv[2]);  printf(main() about to call sem_timedwait()/n);  while ((s = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR)  continue; /* Restart if interrupted by handler */  /* Check what happened */  if (s == -1)     if (errno == ETIMEDOUT)  printf(sem_timedwait() timed out/n);  else  perror(sem_timedwait);     else  printf(sem_timedwait() succeeded/n);  exit((s == 0) ? EXIT_SUCCESS : EXIT_FAILURE);  

我应该如何用计数模拟 sem_wait?

【中文标题】我应该如何用计数模拟 sem_wait?【英文标题】:How should I simulate sem_wait with a count? 【发布时间】:2015-06-06 12:10:50 【问题描述】:

我正在使用semaphore.h,如果n 而不是只有一个插槽可用,我想获得一个信号量。 Posix 本身不提供此功能。我该如何解决这个问题?我一定会使用信号量,没有其他同步方式是可能的。

我正在考虑使用带有单独计数器变量的二进制信号量,但在我看来,这会破坏它的目的。

【问题讨论】:

相关:***.com/questions/3491762 -- 仅声明本机不支持此功能,但不提供没有 SysV 的替代方案 该链接上的答案使用pthread_mutex_tpthread_cond_t 实现了一个信号量。你不能用那个吗? 您可以简单地通过尝试等待计数次数来执行sem_trywait 计数,如果任何失败,sem_post 的次数与重置计时器成功次数一样多。 (类似地,sem_post 只需调用 sem_post 计数次数。)。如果你想要阻塞等待,你需要在一个结构中有两个信号量,这意味着必须包装所有标准的sem_xxx 函数。你能接受吗? 你可以使用系统 V 信号量而不是 POSIX 信号量吗? SysV 版本更难使用,但我认为它确实支持您描述的行为。 感谢您的回复。 @mtijanic,不,这是作业的一部分,看来他们坚持使用信号量(和 posix)。 【参考方案1】:

由于您有多个线程争用信号量的插槽(否则您根本不需要信号量),您需要防止死锁。例如,如果您的信号量有四个插槽,并且两个线程中的每一个都试图获得三个,那么如果每个线程都设法获得两个,它们就会死锁。因此,您必须保护对获取信号量槽的过程的访问。

保护计数器的二进制信号量不足以防止上述死锁情况。此外,如果在任何给定时间没有足够的插槽可用,那么您必须有一些同步方法来等待更多插槽可用。不过,您可以使用两个信号量来完成这项工作,一个用于保护对信号量获取过程的访问,另一个用于承载正在获取的实际插槽。像这样的东西,例如:

#define DO_OR_RETURN(x) do  int _r; if ((_r = (x))) return _r;  while (0)

typedef struct multi_sem 
    sem_t sem_acquire_sem;
    sem_t multislot_sem;
 multisem;

int multisem_init(multisem *ms, unsigned int slots) 
    DO_OR_RETURN(sem_init(&ms->sem_acquire_sem, 0, 1));
    return sem_init(&ms->multislot_sem, 0, slots);


int multisem_wait(multisem *ms, unsigned int slots_to_acquire) 
    int result;
    DO_OR_RETURN(sem_wait(&ms->sem_acquire_sem));

    while (slots_to_acquire) 
        result = sem_wait(&ms->multislot_sem);
        switch (result) 
            case 0:
                slots_to_acquire -= 1;
                break;
            case EINTR:
                /* interrupted by a signal; try again */
                break;
            default:
                /* undocumented error - should never happen */
                /* insert appropriate apocalypse response here */
                slots_to_acquire = 0; /* bail out */
                break;
        
    

    if (sem_post(&ms->sem_acquire_sem)) 
        /* big oops - no recovery possible - should never happen */
        /* insert appropriate apocalypse response here */
    

    return result;


int multisem_post(multisem *ms, unsigned int slots_to_post) 
    while (slots_to_post) 
        DO_OR_RETURN(sem_post(&ms->multislot_sem));
        slots_to_post -= 1;
    
    return 0;

请注意,如果线程尝试获取multisem 的插槽,而它已经拥有至少一个(以及其他方式),那么它仍然容易发生死锁。我认为风险是问题所固有的。

【讨论】:

以上是关于sem_wait的范例的主要内容,如果未能解决你的问题,请参考以下文章

C内存共享进程通信范例

从 C `goto` 错误处理范例转换到 C++ 异常处理范例

增删改查 的网页范例

推荐几个范例项目

范例项目

多线程——范例:建立与启动两个线程 与 范例:显示调度器有多个不可预测的结果(Head First Java的例子)