看了APUE的chapter15,只重点看了15.10,学习了posix信号量。Posix信号量比起xsi信号量的优点是性能更好,在Linux3.2.0平台上性能提升很大。其中命名信号量使用方法如下。

1、  头文件#include <semaphore.h>

2、  函数:

(1)sem_t* sem_open(const char * name,int oflag, mode_t mode, unsigned int value)

这个函数是在使用之前先创建信号量,name是你要创建这个命名信号量的字符串名字。Name必须以/开头,并且后面不许再有/。

Oflag一般有两种取值,O-CREAT和O-CREAT|O-EXCL。取值为O-CREAT时候,需要提供全部四个参数的值。如果信号量不存在,则创建一个新的,如果存在,则使用,并没有初始化发生。取值为O-CREAT|O-EXCL时候,也需要提供全部四个参数的值,如果信号量已经存在,sem_open会出错。

mode的值类似Linux文件的权限码。用户读(4)、用户写(2)、用户执行(1),组读(4)、组写(2)、组执行(1),其他读(4)、其他写(2),其他执行(1)。例如网上别人代码的mode取0644,表示当前用户有读写权限,组用户和其他用户只有读权限。(Linux文件的权限修改是chmod 740 文件名,数字前没有0,与这里的不同。可能是命令自动把后面的740当成8进制数来操作。)C程序设计上说,以零开头的是8进制数。网上查网页上说:mode_t是无符号int类型。参考网页---- 《mkdir()函数、mode_t参数》,mkdir和 chmod中的mode也有类似的用法。

如果只使用已存在的命名信号量的值,只要提供name,oflag的值设为0,就可以了。

value是这个这个信号量的初始值,如果是二元信号量的话,一般取1。

函数运行成功的话,会返回一个指向sem_t结构体的指针,这个结构体就是刚刚创建的信号量。出错时返回SEM_FAILED。

sem_open创建的这个sem_t结构体,可能是在内核中开辟的。网上说:有名信号量是随内核持续的,所以如果如果我们不调用sem_unlink来删除它,它将一直存在,直到内核重启(如果一个进程创建了有名信号灯,并退出,那么这个信号灯依然存在)。网上说:有名sem_t是放在文件,无名的sem_t是放在内存。

(2)int sem_wait(sem_t* sem)

创建好信号量之后,如果要获取锁,就使用sem_wait,如果信号量的值此时为0,这个wait会使得当前的wait线程休眠,直到信号量的值为1,当前线程才能被唤醒,从而获取到锁,并执行信号量的值减1动作。

(3)int sem_post(sem_t* sem)

sem_post是释放锁的动作,会使得信号量的值加1,释放当前线程获取到的锁。

(4)int sem_close(sem_t* sem)

如果不使用信号量,需要将其关闭,可能是释放创建信号量时开辟的内存。函数参数是sem_t类型的指针。

(5)int sem_unlink(char* name)

这个函数用于从内核中销毁一个命名信号量。在sem_close执行后执行。

(2)(3)(4)(5)函数如果执行失败,会返回什么样的值,目前还不知道。

下面写一些测试代码:

gcc main.c -o main -lpthread

注意:从word拷贝到txt文本中,双引号的格式不对,需要修改为英文的双引号。需要包含<fcntl.h> ,O_CREAT是在这个文件中定义的。将sem_t*变量设置为全局变量,方便每个线程使用。

测试的时候出现的问题:第一次运行main,运行良好。Ctrl+C结束进程之后,第二次运行main,出现线程死锁现象。原因是,没有执行代码sem_unlink,导致后面重新使用原来存在的命名信号量,但它被之前的进程锁住了,为0。后面的进程想获取锁,就被死锁了。网上资料:进程结束之后,内核不会为进程获取的锁解锁。重启系统(内核),信号量消失,又可以使用了。

解决办法:将子线程的无限循环改为50次循环,从而执行母线程的退出代码:sem_close和sem_unlink,确保退出前销毁信号量。同时在每个线程释放锁之后 ,空循环10000次(10000次才能达到良好效果,5000不保险),使得另外一个线程有足够时间被唤醒,竞争到锁,不至于某个线程一直获取到锁(这个是南京华为的面试官问我的题目:多线程编程有没有遇到某个线程运行速度足够快,从而反复获得锁。我回来测试发现,的确有这种现象)。

修改后的代码放后面。

main.c

#include <semaphore.h>

#include <pthread.h>

#include <stdio.h>

#include <fcntl.h>      //O_CREAT

sem_t* sem1;

sem_t* sem2;

void* thfunc1(void* arg)

{

for(;;)

{

sem_wait(sem1);

printf("This is thread1 printing!\n");

sem_post(sem1);

}

return((void*)0);

}

void* thfunc2(void* arg)

{

for(;;)

{

sem_wait(sem1);

printf("This is thread2 printing!\n");

sem_post(sem1);

}

return((void*)0);

}

int main(int argc,char* argv[])

{

const char* c1 = "/wang_sem1";

int res;

pthread_t tid1,tid2;

void* c;

sem1 = sem_open(c1,O_CREAT,0644,1);

res = pthread_create(&tid1,NULL,thfunc1,NULL);

if(res!=0){

printf("can’t creat thread: %s\n",strerror(res));

}

res = pthread_create(&tid2,NULL,thfunc2,NULL);

if(res!=0){

printf("can’t creat thread: %s\n",strerror(res));

}

pthread_join(tid1,&c);

pthread_join(tid2,&c);

sem_close(sem1);

res = sem_unlink(c1);

if(res!=0)

printf("can’t delete semaphore\n");

return(0);

}

修改后的main.c

#include <semaphore.h>

#include <pthread.h>

#include <stdio.h>

#include <fcntl.h>      //O_CREAT

sem_t* sem1;

sem_t* sem2;

void* thfunc1(void* arg)

{

int i,j;

for(i=0;i<50;i++)             //for(;;)

{

sem_wait(sem1);

printf("This is thread1 printing!\n");

sem_post(sem1);

for (j=0;j<10000;j++)

{

}

}

return((void*)0);

}

void* thfunc2(void* arg)

{

int i,j;

for(i=0;i<50;i++)          //for(;;)

{

sem_wait(sem1);

printf("This is thread2 printing!\n");

sem_post(sem1);

for (j=0;j<10000;j++)

{

}

}

return((void*)0);

}

int main(int argc,char* argv[])

{

const char* c1 = "/wang_sem1";

int res;

pthread_t tid1,tid2;

void* c;

sem1 = sem_open(c1,O_CREAT,0644,1);

res = pthread_create(&tid1,NULL,thfunc1,NULL);

if(res!=0){

printf("can’t creat thread: %s\n",strerror(res));

}

res = pthread_create(&tid2,NULL,thfunc2,NULL);

if(res!=0){

printf("can’t creat thread: %s\n",strerror(res));

}

pthread_join(tid1,&c);

pthread_join(tid2,&c);

sem_close(sem1);

res = sem_unlink(c1);

if(res!=0)

printf("can’t delete semaphore\n");

return(0);

}

多线程编程之Apue3rd_Chapter15.10之posix信号量的更多相关文章

  1. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  2. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  3. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  4. [转]iOS多线程编程之NSThread的使用

    1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...

  5. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  6. 深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  7. [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  8. [转]c++多线程编程之pthread线程深入理解

    多线程编程之pthread线程深入理解         Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一 ...

  9. [转] iOS多线程编程之NSOperation和NSOperationQueue的使用

    <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...

随机推荐

  1. 控制台执行java找不到或无法加载主类

  2. 【Leetcode】【Easy】Implement strStr()

    Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...

  3. wmware共享磁盘redhat 5.8挂载问题

    需要修改参数vi /etc/sysconfig/selinux将SELINUX=enforcing改为SELINUX=disabled,这样重启服务器则不会启动selinux服务 不然重启虚拟机后共享 ...

  4. 林锐:5 C++/C程序的基本概念

    5.1.1 main 不能重载 不能内联 不能定义为static 不能取其地址 不能由用户直接调用 5.1.3内部名称 struct Sample_1 { int count; }; struct S ...

  5. ABAP OPEN SQL里OPEN CURSOR和SELECT的比较

    OPEN CURSOR After the OPEN CURSOR statement, the database cursor is positioned in front of the first ...

  6. Hibernate中一对多关联关系中的级联属性

    如果想通过级联属性删除一端的数据和多端的数据要使用 void org.hibernate.Session.delete(Object arg0) 方法. getSession().delete(tea ...

  7. ACM-ICPC(11/9)

    今天看了一下黑书,感觉很刘汝佳,是他的风格,题目挺好的~~~ 枚举 P12翻硬币 二进制枚举每一列的情况2^9种. 在每一种情况下然后对于每一行就是翻与不翻的两种情况~~~ 贪心 P13钓鱼问题 PO ...

  8. SPOJ8093【JZPGYZ - Sevenk Love Oimaster】

    怎么全是广义后缀自动机,我\(AC\)自动机不服 这道题可以使用的算法很多,\(SA\)或者\(SAM\)应该都可以 但是我都不会 但是这毕竟是一个多串匹配问题,\(AC\)自动机还是可以刚一刚的 我 ...

  9. Golang Failpoint 的设计与实现

    小结: 1. https://mp.weixin.qq.com/s/veIoupLjM4l5SUVC6h_Gkw Golang Failpoint 的设计与实现 原创: 龙恒 PingCAP 今天  

  10. ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(七)之 图文,附件消息(2016-05-05 12:13)

    上一篇介绍了加好友的流程,这里不再赘述,不过之前的聊天只能发送普通文字,那么本篇就教你如何实现发送附件和图片消息.我们先对功能进行分析: 发送图片,附件,需要实现上传图片和附件的功能. textare ...