精华内容
下载资源
问答
  •  函数sem_open创建一个新的有名信号灯或打开一个已存在的有名信号灯。有名信号灯总是既可用于线程间的同步,又能用于进程间的同步。 1. sem_open 名称:: sem_open 功能: 创建并初始化有名信号灯 头文件: #...

    一、Posix有名信号灯

    1.posix有名信号灯函数

       函数sem_open创建一个新的有名信号灯或打开一个已存在的有名信号灯有名信号灯总是既可用于线程间的同步,又能用于进程间的同步。

    1. sem_open

    名称::
    sem_open
    功能:
    创建并初始化有名信号灯
    头文件:
    #include 
    函数原形:
    sem_t *sem_open(const char *name,int oflag,/*mode_t mode,unsigned int value*/);
    参数:
    name   信号灯的外部名字
    oflag   选择创建或打开一个现有的信号灯
    mode 权限位
    value 信号灯初始值
    返回值:
    成功时返回指向信号灯的指针,出错时为SEM_FAILED
          
    oflag参数能是0、O_CREAT(创建一个信号灯)或O_CREAT|O_EXCL(如果没有指定的信号灯就创建),如果指定了O_CREAT,那 么第三个和第四个参数是需要的;其中mode参数指定权限位,value参数指定信号灯的初始值,通常用来指定共享资源的书面。该初始不能超过 SEM_VALUE_MAX,这个常值必须低于为32767。二值信号灯的初始值通常为1,计数信号灯的初始值则往往大于1。
       如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号灯尚未存在时才初始化他。所需信号灯已存在条件下指定O_CREAT不是个错 误。该标志的意思仅仅是“如果所需信号灯尚未存在,那就创建并初始化他”。不过所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是个错误。
       sem_open返回指向sem_t信号灯的指针,该结构里记录着当前共享资源的数目。

    复制代码

     

    /*semopen.c*/
    #include
    #include
    #include
    #include
    #include

    int main(int argc,char **argv)
    {
    sem_t *sem;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],O_CREAT,0644,1);
    exit(0);
    }

    复制代码

     

    2. sem_close

    名称::
    sem_close
    功能:
    关闭有名信号灯
    头文件:
    #include 
    函数原形:
    int sem_close(sem_t *sem);
    参数:
    sem 指向信号灯的指针
    返回值:
    若成功则返回0,否则返回-1。

       一个进程终止时,内核还对其上仍然打开着的所有有名信号灯自动执行这样的信号灯关闭操作。不论该进程是自愿终止的还是非自愿终止的,这种自动关闭都会发生。
       但应注意的是关闭一个信号灯并没有将他从系统中删除。这就是说,Posix有名信号灯至少是随内核持续的:即使当前没有进程打开着某个信号灯,他的值仍然保持。

    3. sem_unlink

    名称::
    sem_unlink
    功能:
    从系统中删除信号灯
    头文件:
    #include 
    函数原形:
    int sem_unlink(count char *name);
    参数:
    name   信号灯的外部名字
    返回值:
    若成功则返回0,否则返回-1。

    有名信号灯使用sem_unlink从系统中删除。
    每个信号灯有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才能把name所指的信号灯从文件系统中删除。也就是要等待最后一个sem_close发生。
     

    复制代码

     

    /*semunlink.c*/
    #include
    #include
    #include
    #include
    #include

    int main(int argc,char **argv)
    {
    sem_t *sem;
    int val;
    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    if((sem_unlink(argv[1]))!=0)
    perror(“sem_unlink”);
    else
    printf(“success”);
    exit(0);
    }

    复制代码

     

     

     

    4. sem_getvalue

    名称::
    sem_getvalue
    功能:
    测试信号灯
    头文件:
    #include 
    函数原形:
    int sem_getvalue(sem_t *sem,int *valp);
    参数:
    sem 指向信号灯的指针
    返回值:
    若成功则返回0,否则返回-1。
    sem_getvalue在由valp指向的正数中返回所指定信号灯的当前值。如果该信号灯当前已上锁,那么返回值或为0,或为某个负数,其绝对值就是等待该信号灯解锁的线程数。

    代码

    复制代码

     

    /*semgetvalue.c*/
    #include
    #include
    #include
    #include
    #include

    int main(int argc,char **argv)
    {
    sem_t *sem;
    int val;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],0);
    sem_getvalue(sem,&val);
    printf(“getvalue:value=%d\n”,val);
    exit(0);
    }

    复制代码

     

     

     

    5. sem_wait/sem_trywait

    名称::
    sem_wait/sem_trywait
    功能:
    等待共享资源
    头文件:
    #include 
    函数原形:
    int sem_wait(sem_t *sem); 
    int sem_trywait(sem_t *sem);
    参数:
    sem 指向信号灯的指针
    返回值:
    若成功则返回0,否则返回-1。

    我们能用sem_wait来申请共享资源,sem_wait函数能测试所指定信号灯的值,如果该值大于0,那就将他减1并即时返回。我们就能使用申请来的 共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将他减1,函数随后返回。sem_wait操作必须是原子的。 sem_wait和sem_trywait的差别是:当所指定信号灯的值已是0时,后者并不将调用线程投入睡眠。相反,他返回一个EAGAIN错误。

    下面的程式我们先不去运行,稍后再运行。

     

    代码

    复制代码

     

    /*semwait.c*/
    #include
    #include
    #include
    #include
    #include

    int main(int argc,char **argv)
    {
    sem_t *sem;
    int val;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],0);
    sem_wait(sem);
    sem_getvalue(sem,&val);
    printf(“pid %ld has semaphore,value=%d\n”,(long)getpid(),val);
    pause();
    exit(0);
    }

    复制代码

     

     

    6. sem_post

    名称::
    sem_post
    功能:
    挂出共享资源
    头文件:
    #include 
    函数原形:
    int sem_post(sem_t *sem);
    int sem_getvalue(sem_t *sem,int *valp);
    参数:
    sem 指向信号灯的指针
    返回值:
    若成功则返回0,否则返回-1。

    当一个线程使用完某个信号灯时,他应该调用sem_post来告诉系统申请的资源已用完。本函数和sem_wait函数的功能正好相反,他把所指定的信号灯的值加1,然后唤醒正在等待该信号灯值变为正数的任意线程。

    下面的程式我们先不去运行,稍后再运行。

    代码

    复制代码

     

    /*sempost.c*/
    #include
    #include
    #include
    #include
    #include

    int main(int argc,char **argv)
    {
    sem_t *sem;
    int val;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],0);
    sem_post(sem);
    sem_getvalue(sem,&val);
    printf(“value=%d\n”, val);
    exit(0);
    }

    复制代码

     

     

     

    二. 关于posix有名信号灯使用的几点注意

    我们要注意以下几点:
    1.Posix有名信号灯的值是随内核持续的。也就是说,一个进程创建了一个信号灯,这个进程结束后,这个信号灯还存在,并且信号灯的值也不会改动。
    下面我们利用上面的几个程式来证实这点
    #./semopen test
    #./semgetvalue test
    value=1   信号的值仍然是1

    2。当持有某个信号灯锁的进程没有释放他就终止时,内核并不给该信号灯解锁。
    #./semopen test
    #./semwait test&
    pid 1834 has semaphore,value=0 
    #./semgetvalue test 
    value=0 信号量的值变为0了

    3.posix有名信号灯应用于多线程
    #include 
    #include 
    #include 
    #include 
    #include 

    void *thread_function(void *arg); /*线程入口函数*/
    void print(pid_t); /*共享资源函数*/
    sem_t *sem; /*定义Posix有名信号灯*/
    int val; /*定义信号灯当前值*/

    int main(int argc,char *argv[])
    {
    int n=0;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],O_CREAT,0644,3); /*打开一个信号灯*/

    while(n++循环创建5个子线程,使他们同步运行*/
    {
    if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0)
           {
             perror(“Thread creation failed”);
             exit(1);
          }
    }
    pthread_join(a_thread,NULL);
    sem_close(bin_sem);
    sem_unlink(argv[1]);
    }

    void *thread_function(void *arg)
    {
    sem_wait(sem); /*申请信号灯*/
    print(); /*调用共享代码段*/
    sleep(1); 
    sem_post(sem); /*释放信号灯*/
    printf(“I’m finished,my tid is %d\n”,pthread_self());
    }

    void print()
    {
    printf(“I get it,my tid is %d\n”,pthread_self());
    sem_getvalue(sem,&val);
    printf(“Now the value have %d\n”,val);
    }

    程式用循环的方法建立5个线程,然后让他们调用同一个线程处理函数thread_function,在函数里我们利用信号量来限制访问共享资源的线程数。共享资源我们用print函数来代表,在真正编程中他有能是个终端设备(如打印机)或是一段有实际意义的代码。

    运行结果为:
    #gcc ?lpthread ?o 8_1 8_1.c
    #./8_1 test
    I get it,my tid is 1082330304
    Now the value have 2
    Iget it,my pid is 1894
    Now the value have 1
    Iget it,my pid is 1895
    Now the value have 0
    I’m finished,my pid is 1893
    I’m finished,my pid is 1894
    I’m finished,my pid is 1895
    I get it,my pid is 1896
    Now the value have 2
    I get it,mypid is 1897
    Now the value have 1
    I’m finished,my pid is 1896
    I’m finished,my pid is 1897

    4.posix有名信号灯应用于多进程
    下面就是应用Posix有名信号灯的一个小程序。用它来限制访问共享代码的进程数目。
    #include 
    #include 
    #include 
    #include 

    void print(pid_t);
    sem_t *sem; /*定义Posix有名信号灯*/
    int val; /*定义信号灯当前值*/

    int main(int argc,char *argv[])
    {
    int n=0;

    if(argc!=2)
    {
    printf(“please input a file name!\n”);
    exit(1);
    }
    sem=sem_open(argv[1],O_CREAT,0644,2); /*打开一个信号灯, 初值设为2*/

    while(n++循环创建5个子进程,使它们同步运行*/
    {
    if(fork()==0) 
    {
           sem_wait(sem); /*申请信号灯*/
           print(getpid()); /*调用共享代码段*/
           sleep(1); 
           sem_post(sem); /*释放信号灯*/
           printf(“I’m finished,my pid is %d\n”,getpid());
           return 0; 
    }
    }
    wait(); /*等待所有子进程结束*/
    sem_close(sem);
    sem_unlink(argv[1]);
    exit(0);
    }

    void print(pid_t pid)
    {
    printf(“I get it,my pid is %d\n”,pid);
    sem_getvalue(sem,&val);
    printf(“Now the value have %d\n”,val);
    }

    程序编译后运行会得到如下结果:
    #./8_2 8_2.c
    I get it,my tid is 1082330304
    Now the value have 1
    I get it,my tid is 1090718784
    Now the value have 0
    I finished,my pid is 1082330304
    I finished,my pid is 1090718784
    I get it,my tid is 1099107264
    Now the value have 1
    I get it,my tid is 1116841120
    Now the value have 0
    I finished,my pid is 1099107264
    I finished,my pid is 1116841120
    I get it,my tid is 1125329600
    Now the value have 1
    I finished,my pid is 1125329600

     

    三、基于内存的信号灯

       前面已经介绍了Posix有名信号灯。这些信号灯由一个name参数标识,它通常指代文件系统中的某个文件。然而Posix也提供基于内存的信号灯,它们由应用程序分配信号灯的内存空间,然后由系统初始化它们的值。

    7.
    名称::
    sem_init/sem_destroy
    功能:
    初始化/关闭信号等
    头文件:
    #include 
    函数原形:
    int sem_init(sem_t *sem,int shared,unsigned int value);
    int sem_getvalue(sem_t *sem);
    参数:
    sem 指向信号灯的指针
    shared   作用范围
    value 信号灯初始值
    返回值:
    若成功则返回0,否则返回-1。

    基于内存的信号灯是由sem_init初始化的。sem参数指向必须由应用程序分配的sem_t变量。如果shared为0,那么待初始化的信号灯是在同 一进程的各个线程共享的,否则该信号灯是在进程间共享的。当shared为零时,该信号灯必须存放在即将使用它的所有进程都能访问的某种类型的共享内存 中。跟sem_open一样,value参数是该信号灯的初始值。
       使用完一个基于内存的信号灯后,我们调用sem_destroy关闭它。
    除了sem_open和sem_close外,其它的poisx有名信号灯函数都可以用于基于内存的信号灯。

    注意:posix基于内存的信号灯和posix有名信号灯有一些区别,我们必须注意到这些。
    1.sem_open不需要类型与shared的参数,有名信号灯总是可以在不同进程间共享的。
    2.sem_init不使用任何类似于O_CREAT标志的东西,也就是说,sem_init总是初始化信号灯的值。因此,对于一个给定的信号灯,我们必须小心保证只调用一次sem_init。
    3.sem_open返回一个指向某个sem_t变量的指针,该变量由函数本身分配并初始化。但sem_init的第一个参数是一个指向某个sem_t变量的指针,该变量由调用者分配,然后由sem_init函数初始化。
    4.posix有名信号灯是通过内核持续的,一个进程创建一个信号灯,另外的进程可以通过该信号灯的外部名(创建信号灯使用的文件名)来访问它。 posix基于内存的信号灯的持续性却是不定的,如果基于内存的信号灯是由单个进程内的各个线程共享的,那么该信号灯就是随进程持续的,当该进程终止时它 也会消失。如果某个基于内存的信号灯是在不同进程间同步的,该信号灯必须存放在共享内存区中,这要只要该共享内存区存在,该信号灯就存在。
    5.基于内存的信号灯应用于线程很麻烦(待会你会知道为什么),而有名信号灯却很方便,基于内存的信号灯比较适合应用于一个进程的多个线程。

    下面是posix基于内存的信号灯实现一个进程的各个线程间的互次。
    #include 
    #include 
    #include 
    #include 
    #include 
    #incude 

    void *thread_function(void *arg); /*线程入口函数*/
    void print(void); /*共享资源函数*/

    sem_t bin_sem; /*定义信号灯*/
    int value; /*定义信号量的灯*/

    int main()
    {
    int n=0;
    pthread_t a_thread; 

    if((sem_init(&bin_sem,0,2))!=0) /*初始化信号灯,初始值为2*/
    {
    perror(“sem_init”);
    exit(1);
    }
    while(n++循环创建5个线程*/
    {
    if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0) 
    {
    perror(“Thread creation failed”);
    exit(1);
    }
    }
    pthread_join(a_thread,NULL);/*等待子线程返回*/
    }

    void *thread_function(void *arg)
    {
    sem_wait(&bin_sem); /*等待信号灯*/
    print();
    sleep(1);
    sem_post(&bin_sem); /*挂出信号灯*/
    printf(“I finished,my pid is %d\n”,pthread_self());
    pthread_exit(arg);
    }

    void print()
    {
    printf(“I get it,my tid is %d\n”,pthread_self());
    sem_getvalue(&bin_sem,&value); /*获取信号灯的值*/
    printf(“Now the value have %d\n”,value);
    }

       posix基于内存的信号灯和有名信号灯基本是一样的,上面的几点区别就可以了。 
    下面是运行结果:
    #gcc –lpthread –o seminitthread seminitthread.c
    #./seminitthread 
    I get it,my tid is 1082330304
    Now the value have 1
    I get it,my tid is 1090718784
    Now the value have 0
    I finished,my pid is 1082330304
    I finished,my pid is 1090718784
    I get it,my tid is 1099107264
    Now the value have 1
    I get it,my tid is 1116841120
    Now the value have 0
    I finished,my pid is 1099107264
    I finished,my pid is 1116841120
    I get it,my tid is 1125329600
    Now the value have 1
    I finished,my pid is 1125329600

    下面的程序并不能得到我们想要的结果。
    #include 
    #include 
    #include 
    #include 

    void print(pid_t);
    sem_t *sem; /*定义Posix有名信号灯*/
    int val; /*定义信号灯当前值*/

    int main(int argc,char *argv[])
    {
    int n=0;

    sem=sem_open(argv[1],O_CREAT,0644,3); /*打开一个信号灯*/
    sem_getvalue(sem,&val); /*查看信号灯的值*/
    printf(“The value have %d\n”,val);

    while(n++循环创建5个子进程,使它们同步运行*/
    {
    if(fork()==0) 
    {
           sem_wait(sem); /*申请信号灯*/
           print(getpid()); /*调用共享代码段*/
           sleep(1); 
           sem_post(sem); /*释放信号灯*/
           printf(“I’m finished,my pid is %d\n”,getpid());
           return 0; 
    }
    wait(); /*等待所有子进程结束*/
    return 0;
    }

    void print(pid_t pid)
    {
    printf(“I get it,my pid is %d\n”,pid);
    sem_getvalue(sem,&val);
    printf(“Now the value have %d\n”,val);
    }

    下面是运行结果:
    #cc –lpthread –o sem sem.c
    #./sem 
    The value have 3
    I get it,my pid is 2236
    Now the value have 2
    I get it,my pid is 2237
    Now the value have 2
    I get it,my pid is 2238
    Now the value have 2
    I get it,my pid is 2239
    Now the value have 2
    Iget it,my pid is 2240
    Now the value have 2
    I’m finished,my pid is 2236
    I’m finished,my pid is 2237
    I’m finished,my pid is 2238
    I’m finished,my pid is 2239
    I’m finished,my pid is 2240

    问题在于sem信号灯不在共享内存区中。fork出来的子进程通常不共享父进程的内存空间。子进程是在父进程内存空间的拷贝上启动的,它跟共享内存不是一回事。

    展开全文
  • 但是在libc库中,函数sem_opensem_close、sem_unlink只有声明,并未实现。 可以从一下代码中找到证据。 代码路径: bionic/libc/include/semaphore.h /* * Copyright (C) 2008 The Android Open Source Project ...

    在android下使用信号量时,需要链接libc库。

    但是在libc库中,函数sem_open、sem_close、sem_unlink只有声明,并未实现。

    可以从一下代码中找到证据。

    代码路径:
    bionic/libc/include/semaphore.h

    /*
     * Copyright (C) 2008 The Android Open Source Project
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *  * Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in
     *    the documentation and/or other materials provided with the
     *    distribution.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     * SUCH DAMAGE.
     */
    
    #ifndef _SEMAPHORE_H
    #define _SEMAPHORE_H
    
    #include <sys/cdefs.h>
    
    __BEGIN_DECLS
    
    struct timespec;
    
    typedef struct {
      unsigned int count;
    #ifdef __LP64__
      int __reserved[3];
    #endif
    } sem_t;
    
    #define SEM_FAILED __BIONIC_CAST(reinterpret_cast, sem_t*, 0)
    
    int sem_destroy(sem_t* __sem);
    int sem_getvalue(sem_t* __sem, int* __value);
    int sem_init(sem_t* __sem, int __shared, unsigned int __value);
    int sem_post(sem_t* __sem);
    int sem_timedwait(sem_t* __sem, const struct timespec* __ts);
    /*
     * POSIX only supports using sem_timedwait() with CLOCK_REALTIME, however that is typically
     * inappropriate, since that clock can change dramatically, causing the timeout to either
     * expire earlier or much later than intended.  This function is added to use a timespec based
     * on CLOCK_MONOTONIC that does not suffer from this issue.
     */
    int sem_timedwait_monotonic_np(sem_t* __sem, const struct timespec* __ts) __INTRODUCED_IN(28);
    int sem_trywait(sem_t* __sem);
    int sem_wait(sem_t* __sem);
    
    /* These aren't actually implemented. */
    sem_t* sem_open(const char* __name, int _flags, ...);
    int sem_close(sem_t* __sem);
    int sem_unlink(const char* __name);
    
    __END_DECLS
    
    #endif
    
    

    后记:
    安卓中通信这块和linux还是有很大不同的。坑很多。。。。

    展开全文
  • sem_open() sem_wait() sem_post()

    千次阅读 2013-04-11 12:40:08
    1 .sem_open() 函数说明:创建并初始化有名信号灯。 头文件:#include 函数原型: sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value);参数: name 信号灯的外部名字 oflag ...

    这三个函数是在应用层使用信号量的操作函数, 具体作用如下:

    1 .sem_open()

    函数说明:创建并初始化有名信号灯。

    头文件:#include <semaphore.h>
    函数原型:
    sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value);
    参数:
    name 信号灯的外部名字
    oflag 选择创建或打开一个现有的信号灯
    mode 权限位
    value 信号灯初始值
    返回值:
    成功时返回指向信号灯的指针,出错时为SEM_FAILED
    oflag参数可以是0、O_CREAT(创建一个信号灯)或O_CREAT|O_EXCL(如果没有指定的信号灯就创建),如果指定了O_CREAT,那么第三个和第四个参数是需要的;其中mode参数指定权限位,value参数指定信号灯的初始值,通常用来指定共享资源的书面。该初始不能超过SEM_VALUE_MAX,这个常值必须低于为32767。二值信号灯的初始值通常为1,计数信号灯的初始值则往往大于1。
    如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号灯尚未存在时才初始化它。所需信号灯已存在条件下指定O_CREAT不是一个错误。该标志的意思仅仅是“如果所需信号灯尚未存在,那就创建并初始化它”。但是所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是一个错误。
    sem_open返回指向sem_t信号灯的指针,该结构里记录着当前共享资源的数目。
    例子:
      #include <semaphore.h>
      #include <unistd.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <fcntl.h>
      int main(int argc,char **argv)
      {
      sem_t *sem;
      if(argc!=2)
      {
      printf(“please input a file name!\n”);
      exit(1);
      }
      sem=sem_open(argv[1],O_CREAT,0644,1);
      exit(0);
      }
    2. sem_wait(), sem_trywait(), sem_timedwait()
    函数原形:
    int sem_wait(sem_t * sem);
    函数作用:
    sem_wait函数也是一个 原子操作,它的作用是从 信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。
    也就是说,如果你对一个值为2的 信号量调用sem_wait(), 线程将会继续执行,这信号量的值将减到1。
    如果对一个值为0的 信号量调用sem_wait(),这个函数就 会地等待直到有其它 线程增加了这个值使它不再是0为止。
    如果有两个 线程都在sem_wait()中等待同一个 信号量变成非零值,那么当它被第三个线程增加 一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
    sem_wait() 减小(锁定)由sem指定的信号量的值.如果信号量的值比0大,
    那么进行减一的操作,函数立即返回.
    如果信号量当前为0值,那么调用就会一直阻塞直到或者是信号量变得可以进行减一的操作
    (例如,信号量的值比0大),或者是信号处理程序中断调用
    sem_trywait() 和 sem_wait()是一样的,除了如果不能够对信号量立即进行减一,
    那么sem_trywait()就会返回一个错误(错误号是AGAIN)而不是锁定.
    sem_timedwait() 和 sem_wait()是一样的,除了如果减一操作不能立即执行的话,
    abs_timeout 指定了调用应该被阻塞的时间限制.
    abs_timeout 参数指向了一个结构体指定了由秒和纳秒组成的绝对的超时值:
    从1970-01-01 00:00:00 +0000纪元开始的UTC,结构体的定义如下:
    struct timespec
    {
    time_t tv_sec; /* Seconds */
    long tv_nsec; /* Nanoseconds [0 .. 999999999] */
    };
    如果超时值已经超过了调用规定的值,那么信号量不能被立即锁定,
    之后sem_timedwait() 为超时失败(error设置为ETIMEDOUT).
    如果操作立即生效,那么sem_timedwait() 永远不会返回超时的错误,不管abs_timeout的值.
    更进一步的是,在这种情况下abs_timeout值的有效性都不会检查.
    返回值:
    所有的函数成功返回0,错误的话信号量的值不改动,返回-1.errno设定来标识错误.
    EINTR
    The call was interrupted by a signal handler; see signal(7). //调用被信号处理中断
    EINVAL
    sem is not a valid semaphore.   //sem不是有效的信号量
    The following additional error can occur for sem_trywait():  //下面的错误是sem_trywait()可能发生的:
    EAGAIN
    The operation could not be performed without blocking (i.e., the semaphore currently has the value zero).  //除了锁定无法进行别的操作(如信号量当前是0值).
    The following additional errors can occur for sem_timedwait():
    //下面的错误是sem_timedwait()可能发生的:
    EINVAL
    The value of abs_timeout.tv_nsecs is less than 0, or greater than or equal to 1000 million. //abs_timeout.tv_nsecs 的值比0小或者大于等于1000毫秒(译者注:纳秒的值不能比0小,不能比1秒大)
    ETIMEDOUT 
    The call timed out before the semaphore could be locked. //在信号量锁定之前就超时了
    范例:
    //(有些琐碎的)程序以下展示了在一个未命名的信号量上的操作.程序请求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);
    }
    3. sem_post()
    函数原形:
    int sem_post(sem_t *sem);
    sem_post函数的作用是给 信号量的值加上一个“1”,它是一个“ 原子操作”---即同时对同一个信号量做加“1”操作的两个 线程是不会冲突的;而同 时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。 信号量的值永远会正确地加一个“2”--因为有两个 线程试图改变它。
    返回值:
    sem_post() 成功时返回 0;错误时, 信号量的值没有更改,-1 被返回,并设置 errno 来指明错误。
    错误:
    EINVAL    //sem 不是一个有效的信号量。
    EOVERFLOW   //信号量允许的最大值将要被超过。






    展开全文
  • sem_init函数用法

    千次阅读 2020-12-05 14:39:34
    sem_init函数 sem_init函数是Posix信号量操作中的函数sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 ...

    sem_init函数

    • sem_init函数是Posix信号量操作中的函数。sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。
    • 如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。因为通过 fork(2) 创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。所有可以访问共享内存区域的进程都可以用 sem_post(3)、sem_wait(3) 等等操作信号量。初始化一个已经初始的信号量其结果未定义。
    • 返回值
      sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。
    • 用下面一组函数(系统调用)来实现。
    int sem_init(sem_t *sem,int pshared,unsigned int value); 
    int sem_destroy(sem_t *sem); 
    int sem_wait(sem_t *sem); 
    int sem_trywait(sem_t *sem); 
    int sem_post(sem_t *sem); 
    int sem_getvalue(sem_t *sem); 
    
    • List item

    具体要Include什么头文件,在你的系统上man sem_init吧。
    这组函数是POSIX标准的无名信号量函数,另外还有具名信号亮,这个嘛,等下回再说。

    • 第一个参数:信号量名

    看一个例子,比如有两个线程都要往打印机上打东西,但是同一时刻只能打一个。那么首先用sem_init初始化一个信号量,注意pshared表示允许几个进程共享该信号量,一般设0用于进程内的多线程共享,要看是否支持进程共享,请查看下你的系统的man手册。

    • 第三个参数value表示可用的资源的数目,即信号灯的数目,咱们这儿只有1个打印机所以设成1。然后线程调用sem_wait取获取这个信号灯,第一个线程一看,有1个,他就拿到了,然后可以继续后继操作,此时信号灯自动减1,变成0个。那么第二个线程调用sem_wait时就会阻塞在这儿了。第一个线程完成打印后,调用sem_post释放信号灯,信号灯数目变成1,将会唤醒等待的第二个线程,然后第二个线程接着打印。最后当所有任务完成后,主线程调用sem_destroy释放这个信号量。
    展开全文
  • 有名信号量sem_open和内存信号量sem_init创建信号量的区别  分类: C/C++ sem_t *sem sem_open(const char *name, int oflag, .../*mode_t mode,unsinged int value) ; int sem_init(sem_t *sem,int ...
  • Linux sem_init函数用法

    2021-08-27 01:09:41
    sem_init函数是Posix信号量操作中的函数。 int sem_init(sem_t *sem,int pshared,unsigned int value); sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量...
  • 版权声明:本文为博主原创文章,未经博主允许不得...一、sem_open函数name参数的构造 Linux的有名信号量的创建是通过调用sem_open函数创建的,函数原型如下: 我刚开始用以为是想一般的指定一个路径名给sem_op...
  • Linux的有名信号量的创建是通过调用sem_open函数创建的,
  • C函数篇(sem_init函数)

    2019-08-15 13:07:34
    函数原型 int sem_init(sem_t *sem, int pshared, unsigned int value); 说明 sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是...
  • sem_open中文件名参数使用说明

    千次阅读 2014-12-09 17:11:01
    #include /* For O_* constants */ #include /* For mode constants */ #include sem_t *sem_open(const char *name, int oflag);...sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int val
  • 学习信号量 sem_init、sem_destroy、sem_post、sem_wait、sem_trywait、sem_getvalue 概要: 1.信号量使用场合 2.POSIX标准定义的信号量 2.1 sem_init、sem_destroy、sem_post、sem_wait、sem_trywait、sem_getvalue...
  • sem_init函数

    千次阅读 2012-09-23 09:36:36
     int sem_init(sem_t *sem, int pshared, unsigned int value);    sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程...
  • 内存信号量sem_init函数解析

    千次阅读 2014-03-12 16:11:51
    int sem_init(sem_t *sem, int pshared, unsigned int value); return 0 on success,or -1 on error 本文着重解析sem_init第二个参数 pshared ,下面摘自《The Linux Programming Interface》 这一段...
  • sem_open 和 errno的使用问题

    千次阅读 2010-09-29 10:39:00
    使用共享库,遇到一个sem_open的问题。   当时的写法是: sem_open( pSemName, O_CREATE | O_RDWT); 编译通过,但程序执行到此时,就崩了。 后来查看errno后,得到是参数错误。...
  • sem_open出现段错误 名字问题

    千次阅读 2011-10-29 10:54:11
    posix信号灯里面的这个函数sem_open();这里面的第一个参数一般情况下第一个字符为'/' 而且后面的的字符串里面不能在中间出现反斜杠,因为这种有名信号灯的实现机制是依靠文件的方式来实现的.而反斜杠后面的为这个...
  • #include /* For O_* constants */ #include /* For mode constants */ #include #include #include ...#define SEM_NAME "MY_SEM_NAME" bool bExitThread = false; sem_t *g_sem; pthread_t g
  • 哈工大操作系统实验 信号量的实现 pc.c 编译时报错 对’sem_open’未定义的引用 解决方式: 编译时加入选项 -pthread
  • NAME semaphore.h - semaphores (REALTIME) ...[SEM]#include <semaphore.h> DESCRIPTION The<semaphore.h>header shall define thesem_ttype, used in performing semaphore o...
  • 我现在写了一个xx.a库,里面使用了sem_open函数,如果将这个.a交给第三方使用,如果不添加-pthread这个命令 会提示undefined reference to `sem_open undefined reference to `sem_post 。 能不能在我生成.a的...
  • shm_open函数实例及说明

    万次阅读 2017-11-05 18:34:20
    使用shm_open来操作共享内存 shm_open最主要的操作也是默认的操作就是在/dev/shm/下面,建立一个文件。 文件名字是用户自己输入的。 要点一定要用ftruncate把文件大小于设置为共享内存大小。 ...
  • sem_open()

    千次阅读 2005-03-08 11:07:00
    书上介绍的很多了,不多说了!问题:编译成功,连接失败。解决:老迈和秃子提示:man终于找到这个一个冬冬: To use this function, link in the realtime library by specifying -lrt on the compiler or linker ...
  • 终端设备驱动之tty_open函数

    千次阅读 2012-05-11 09:29:27
    tty_open函数源码: static int tty_open(struct inode * inode, struct file * filp) { ...... retval = init_dev(device, &tty);调用此函数,为需要打开的终端设备建立一个(或找到其)tty_struct数据结构...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,183
精华内容 4,473
关键字:

sem_open函数