信号量sem

您所在的位置:网站首页 pthread_mutex_lock_full 信号量sem

信号量sem

#信号量sem| 来源: 网络整理| 查看: 265

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  

extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  T>

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  T>

函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  T>

函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  T>

函数sem_destroy(sem_t *sem)用来释放信号量sem。 T>

信号量用sem_init函数创建的,下面是它的说明:   #include         int sem_init (sem_t *sem, int pshared, unsigned int value);         这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。 (这个参数受版本影响), pshared传递一个非零将会使函数调用失败。   这两个函数控制着信号量的值,它们的定义如下所示:      #include         int sem_wait(sem_t * sem);         int sem_post(sem_t * sem);           这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。         sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。         sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。          信号量这种“只用一个函数就能原子化地测试和设置”的能力下正是它的价值所在。还有另外一个信号量函数sem_trywait,它是sem_wait的非阻塞搭档。          最后一个信号量函数是sem_destroy。这个函数的作用是在我们用完信号量对它进行清理。下面的定义:           #include           int sem_destroy (sem_t *sem);           这个函数也使用一个信号量指针做参数,归还自己战胜的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。          与其它的函数一样,这些函数在成功时都返回“0”。

摘自:百度百科: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 #include #include #include #include #include

#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   perror(strerror(errno));   exit(EXIT_FAILURE);  }    if ( pthread_mutex_init(&mutex, NULL) != 0 ) //互斥锁,保证线程访问的互斥,步骤二,初始化,默认属性初始化互斥量——NULL参数的功能  {   perror(strerror(errno));   exit(EXIT_FAILURE);  }  /*  #include   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/ 感谢作者



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3