互斥锁是为上锁而优化的,条件变量是为等待而优化的,信号灯既可用用于上锁,也可用于等待,因而可能导致更多的开销和更高的复杂性。
Posix.1基本原理一文给出了有了互斥锁和条件变量还提供信号灯的原因:
信号灯的主要目的是提供一种进程间同步方式;这些进程可能共享内存也可能不共享内存区。互斥锁和条件变量是作为线程间的同步机制说明的,这些线程总是共享(某个)内存区。
但是,互斥锁意图是用于线程同步,但是也可以用于进程间同步;而信号灯也可以用于线程间同步。
有名信号灯:
1.sem_t *sem_open(const char *name, int aflag, mode_t mode, unsigned int value);//新建或打开一个信号灯
aflag可以是0、O_CREAT或O_CREATE|O_EXCL。
value指定信号灯的初始值,不能超过SEM_VALUE_MAX,二值信号灯的初始值通常为1,技术信号灯初始值则往往大于1.
2.int sem_close(sem_t *sem);//关闭有名信号灯
3.int sem_unlink(const char *name);//从系统删除有名信号灯,只有到最后一个sem_close调用后信号灯才能拆除。
4.int sem_wait(sem_t *sem);//sem_wait和sem_trywait测试信号灯的值,若大于0,则将它减1并立即返回。
int sem_trywait(sem_t *sem);//sem_trywait当指定信号灯的值已经是0时,后者并不将线程投入睡眠。只是返回一个EAGAIN错误。
5.int sem_post(sem_t *sem);//让所指定信号灯值加1
int sem_getvalue(sem_t *sem, int *valp);//返回指定信号灯的当前值,若信号灯当前已上锁,返回值或为0,或为负数,绝对值为等待信号灯的线程数。
无名信号灯:
int sem_init(sem_t *sem, int shared, unsigned int value);
int sem_destroy(sem_t *sem);
基于内存的信号灯是由sem_init函数初始化的。sem参数指向必须由应用程序分配的sem_t变量,由调用者分配,sem_init初始化。若shared为0,则该信号灯是在同一进程的各个线程间共享的,否则该信号灯是在进程间共享的。当shared为非0时,该信号灯必须存放在即将使用它的所有进程都能访问的某种类型的共享内存区中。
当不需要有名信号灯关联的名字时,可改用基于内存的信号灯。彼此无亲缘关系的不同进程需使用信号灯时,通常使用有名信号灯。其名字就是各个进程标识信号灯的手段。
*)如果某个基于内存的信号灯是由单个进程内的各个线程共享的(shared == 0),那么该信号灯具有随进程的持续性,当该进程终止时它也消失;
*)如果某个基于内存的信号灯是在不同进程间共享的(share == 1),那么该信号灯必须存放在共享内存中,因而只要该内存区存在,该信号灯就存在。
//procons.c
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#define NBUFF 10
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWOTH)
int nitems;
struct
{
int buf[NBUFF];
sem_t *mutex, *nempty, *nstored;
}shared;
void *produce(void *), *consume(void *);
int main(int argc, char **argv)
{
pthread_t tid_produce, tid_consume;
int val;
if(argc != 2)
{
perror("usage: procons <#items>");
exit(0);
}
nitems = atoi(argv[1]);
shared.mutex = sem_open("_mutex", O_CREAT | O_EXCL, FILE_MODE, 1);
shared.nempty = sem_open("_nempty", O_CREAT | O_EXCL, FILE_MODE, NBUFF);
shared.nstored = sem_open("_nstored", O_CREAT | O_EXCL, FILE_MODE, 0);
printf("shared.nempty = %d\n", sem_getvalue(shared.nempty, &val));
pthread_setconcurrency(2);
pthread_create(&tid_produce, NULL, produce, NULL);
pthread_create(&tid_consume, NULL, consume, NULL);
pthread_join(tid_produce, NULL);
pthread_join(tid_consume, NULL);
sem_unlink("_mutex");
sem_unlink("_nempty");
sem_unlink("_nstored");
return 0;
}
void *produce(void *arg)
{
int i;
for(i = 0; i < nitems; i++)
{
sem_wait(shared.nempty);
sem_wait(shared.mutex);
shared.buf[i % NBUFF] = i;
sem_post(shared.mutex);
sem_post(shared.nstored);
printf("produce\n");
}
return NULL;
}
void *consume(void *arg)
{
int i;
for(i = 0; i < nitems; i++)
{
sem_wait(shared.nstored);
sem_wait(shared.mutex);
if(shared.buf[i % NBUFF] == i)
printf("buf[%d] = %d\n", i, shared.buf[i % NBUFF]);
sem_post(shared.mutex);
sem_post(shared.nempty);
printf("consume\n");
}
return NULL;
}
//procons2.c
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#define NBUFF 10
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWOTH)
int nitems;
struct
{
int buf[NBUFF];
sem_t mutex, nempty, nstored;
}shared;
void *produce(void *), *consume(void *);
int main(int argc, char **argv)
{
pthread_t tid_produce, tid_consume;
int val;
if(argc != 2)
{
perror("usage: procons <#items>");
exit(0);
}
nitems = atoi(argv[1]);
sem_init(&shared.mutex, 0, 1);//0 means semaphore is shared among threads in one process
sem_init(&shared.nempty, 0, NBUFF);
sem_init(&shared.nstored, 0, 0);
printf("shared.nempty = %d\n", sem_getvalue(&shared.nempty, &val));
pthread_setconcurrency(2);
pthread_create(&tid_produce, NULL, produce, NULL);
pthread_create(&tid_consume, NULL, consume, NULL);
pthread_join(tid_produce, NULL);
pthread_join(tid_consume, NULL);
sem_destroy(&shared.mutex);
sem_destroy(&shared.nempty);
sem_destroy(&shared.nstored);
return 0;
}
void *produce(void *arg)
{
int i;
for(i = 0; i < nitems; i++)
{
sem_wait(&shared.nempty);
sem_wait(&shared.mutex);
shared.buf[i % NBUFF] = i;
sem_post(&shared.mutex);
sem_post(&shared.nstored);
printf("produce\n");
}
return NULL;
}
void *consume(void *arg)
{
int i;
for(i = 0; i < nitems; i++)
{
sem_wait(&shared.nstored);
sem_wait(&shared.mutex);
if(shared.buf[i % NBUFF] == i)
printf("buf[%d] = %d\n", i, shared.buf[i % NBUFF]);
sem_post(&shared.mutex);
sem_post(&shared.nempty);
printf("consume\n");
}
return NULL;
}
Posix信号灯
最新推荐文章于 2024-04-01 22:29:51 发布