首页 > 编程知识 正文

一般信号量中,c语言信号量

时间:2023-05-05 14:11:11 阅读:113444 作者:234

信号是学习同步的好方法,但实际上不像互斥体和条件变量那样广泛使用。

尽管如此,有些同步问题很容易通过信号量解决,显然产生了更好的解决方案。

本章列出了c语言用于处理信号量的API,以及我用来使它更容易使用的代码。 而且表明了终极的挑战。 可以使用互斥体和条件变量实现信号量吗?

本章的代码位于本书仓库的semaphore目录中。 11.1 POSIX信号量

信号量是用于在互不影响的情况下协作线程的数据结构。

POSIX标准规定信号量接口,而不是pthreadpthreadsem_t。 由于此类型表示为结构,因此为变量赋值将提供其内容的副本。 复制信号量是一种完全不良的行为,POSIX中未定义该复制行为。 幸运的是,打包sem_t使其更安全、更易于使用相当简单。 我的包API在sem.hSemaphoresem_t中是同义词,但我认为它更容易阅读。 此外,大写首字母还会提醒您将其视为对象,并使用指针传递。 这些函数的实现位于Semaphore中

*make_semaphore(intvalue ) semaphore*SEM=check_malloc ) sizeof (semaphore );

intn=SEM_init(SEM,0,value ); if(n!=0) perror _ exit (SEM _ init故障);

返回SEM; }以}make_semaphore接收信号量的初始值为参数。 为信号量分配空间,初始化信号量,然后返回Semaphore

如果执行成功,sem_init返回0。 如果有错误,则返回-1。 包装函数的一个优点是可以包装错误检查代码。 这使使用这些函数的代码更容易阅读。

以下是semaphore_wait的实现:

void semaphore _ wait (semaphore * SEM ) intn=SEM_wait ) SEM; if(n!=0)

perror_exit(SEM_waitfailed ); }接下来

我喜欢把这个操作叫做“信号”而不是“开机自检”。 虽然它们是同样的意思。

译者注:熟悉排他(锁定)操作后,也可以改为锁定和解锁。 互斥体是信号量容量为1时的特殊形态。

一个示例说明如何将信号量用作互斥体。

semaphore * mutex=make _ semaphore (1; semaphore_wait(mutex;//受保护

codegoesheresemaphore _ signal (mutex );

如果hhdts使用信号量作为互斥体,则通常必须将其初始化为1,以指示互斥体未锁定。 这意味着,只有一个线程可以通过信号量而不被阻止。

在这里,我们使用了变量名mutex来指示信号量被用作互斥体。 但是请记住,信号量的行为与pthread互斥体不完全相同。

这些信号量的包装函数可以用来解决生产者-消费者问题。 本节中的代码位于queue_sem.c上。

以下是Queue的新定义: 用信号量代替互斥体和条件变量。

类型结构{ int * array; int length; int next_in; int next_out; Semaphore

*mutex; //-- new Semaphore *items; //- -新semaphore * spaces; //-- new }

队列; 以下为queue*make_queue(intlength ) queue*queue=) queue* )

malloc (尺寸)队列); 队列长度=长度; 队列阵列=(int * ) )。

malloc(length*sizeof ) int ); 队列- next _ in=0; 队列- next _ out=0;

queue-mutex=make_semaphore(1; 队列- items=make _ semaphore (0;

队列空间=make _ semaphore (length-1 ); 返回队列;

}mutex用于确保队列的独占访问,初始值为1,表示独占主体最初未锁定。 itemqueue_popspaces是队列中的剩馀空间数,是可以在不阻止queue_push的情况下执行的线程数。 第一个空间的数量在队列容量下是voidqueue_push(queue )

*队列,int item ) { semaphore _ wait (队列空间);

semaphore _ wait (队列-矩阵; 队列-阵列[队列-

next_in] = item;

queue->next_in = queue_incr(queue, queue->next_in);

semaphore_signal(queue->mutex); semaphore_signal(queue->items);

}要注意queue_push并不需要调用queue_full,因为信号量跟踪了有多少空间可用,并且在队列满了的时候阻塞住生产者。下面是intqueue_pop(Queue

*queue){ semaphore_wait(queue->items); semaphore_wait(queue->mutex); int

item =queue->array[queue->next_out]; queue->next_out =

queue_incr(queue,queue->next_out); semaphore_signal(queue->mutex);

semaphore_signal(queue->spaces); return item; }

这个解决方案在《The Little Book of Semaphores》中的第四章以伪代码解释。

为了使用本书仓库的代码,你需要编译并运行这个解决方案,你应该执行:

$ make queue_sem $ ./queue_sem

任何可以使用信号量解决的问题也可以使用条件变量和互斥体来解决。一个证明方法就是可以使用条件变量和互斥体来实现信号量。

在你继续之前,你可能想要将其做为一个练习:编写函数,使用条件变量和互斥体实现sem.h中的信号量API。你可以将你的解决方案放到本书仓库的mysem.c和mysem.h中,你会在

mysem_soln.c和mysem_soln.h中找到我的解决方案。

如果你在开始时遇到了麻烦,你可以使用下面来源于我的代码的结构体定义,作为提示:

typedef struct { intvalue, wakeups; Mutex *mutex; Cond *cond; }

Semaphore;value是信号量的值。wakeups记录了挂起信号的数量,也就是说它是已被唤醒但是还没有恢复执行的线程数量。wakeups的原因是确保我们的信号量拥有《The

Little Book of

Semaphores》中描述的性质3。mutex提供了value和wakeups的互斥访问,cond是线程在需要等待信号量时所等待的条件变量。

下面是这个结构体的初始化代码:

Semaphore *make_semaphore(intvalue) { Semaphore *semaphore =

check_malloc(sizeof(Semaphore)); semaphore->value = value;

semaphore->wakeups = 0; semaphore->mutex = make_mutex; semaphore->cond

= make_cond; return semaphore; }

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。