信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。
函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。
函数sem_destroy(sem_t *sem)用来释放信号量sem。
信号量用sem_init函数创建的,下面是它的说明:
#include<semaphore.h>
这两个函数控制着信号量的值,它们的定义如下所示:
#include <semaphore.h>
摘自:百度百科:http://baike.baidu.com/view/1461738.htm
1. 创建和销毁
有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。
动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 其中mutexattr用于指定互斥锁属性(见下),如果为NULL则使用缺省属性。
pthread_mutex_destroy ()用于注销一个互斥锁,API定义如下: int pthread_mutex_destroy(pthread_mutex_t *mutex) 销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。
2. 互斥锁属性
互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:
* PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
* PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
3. 锁操作
锁操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。
/*==============================================================================
bufsem.c
功能:主进程负责向队列(就2个元素)写入数据,创建的两个线程负责读取数据。
同步互斥:主进程和线程之间用信号量sem_t进行同步,线程之间依靠互斥锁进行互斥操作。
问题:进程和线程都使用了信号量,可不可以免去互斥锁?
注意:直接编译gcc -o bufsem bufsem.c会出现如下错误
undefined reference to `sem_init'
undefined reference to `sem_post'
undefined reference to `sem_wait'
编译选项需要加入一个多线程
gcc -pthread -o bufsem bufsem.c
*/==============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <errno.h>
#define N 2 //队列中元素的数量
struct _buf_
{
char *buf[N];
int front, rear; //有from和rear,显然是个队列
}BUF;
void * thread_function_r(void *arg); //线程函数
/*
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
__sem为指向信号量结构的一个指针;__pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;__value给出了信号量的初始值。
*/
sem_t sem_r, sem_w; //semphore,信号量,本程序用于保证进程和线程间的同步
pthread_mutex_t mutex; //互斥锁,保证线程访问的互斥,步骤一,定义数据类型
int main(int argc, char *argv[])
{
int res;
pthread_t a_thread_r, b_thread_r; //线程ID变量,与进程类似,进程为pid_t
for (res=0; res<N; res++) BUF.buf[res] = (char*) malloc (30); //为buf指针数组分配空间
BUF.rear = BUF.front = 0;
/*信号量用sem_init函数创建的,下面是它的说明:
#include<semaphore.h>
int sem_init (sem_t *sem, int pshared, unsigned int value);
这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。
*/
res = sem_init(&sem_r, 0, 0);
if ( res != 0)
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
res = sem_init(&sem_w, 0, 2);
if ( res != 0)
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
if ( pthread_mutex_init(&mutex, NULL) != 0 ) //互斥锁,保证线程访问的互斥,步骤二,初始化,默认属性初始化互斥量——NULL参数的功能
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
/*
#include<pthread.h>
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void*(*start_rtn)(void*),void *restrict arg);
返回值:若成功则返回0,否则返回出错编号
返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。
*/
res = pthread_create(&a_thread_r, NULL, thread_function_r, NULL); //创建读取线程一
if ( res != 0 )
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
res = pthread_create(&b_thread_r, NULL, thread_function_r, NULL); //创建读取线程二
if ( res != 0 )
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
while(1) //【功能】主进程执行写入操作
{
sem_wait(&sem_w); //函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。函数sem_destroy(sem_t *sem)用来释放信号量sem。
fputs("Input any words, its words must less than 30: ", stdout);
fgets(BUF.buf[BUF.rear], 30, stdin);
if (strcmp("end\n", BUF.buf[(BUF.front) % N]) == 0 ) break;
BUF.rear = (BUF.rear + 1) % N;
sem_post(&sem_r); //函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。
usleep(1);
}
return 0;
}
void * thread_function_r(void *arg) //【功能】线程负责读取
{
while(1)
{
sem_wait(&sem_r);
pthread_mutex_lock(&mutex); //获取互斥量(互斥锁),另外有pthread_mutex_trylock尝试对互斥量加锁,如果失败返回EBUSY
fprintf(stdout, "Print:BUF.buf[%d] by %u: %s", BUF.front,pthread_self(), BUF.buf[BUF.front]);
BUF.front = (BUF.front + 1) % N;
pthread_mutex_unlock(&mutex); //释放互斥锁
sem_post(&sem_w);
}
}
来自http://canlynet.blog.163.com/blog/static/25501365200911208257812/ 感谢作者