posts - 200, comments - 8, trackbacks - 0, articles - 0

     摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->struct  sembuf {    int sem_num;//下标    in...  阅读全文

posted @ 2013-01-08 12:18 鑫龙 阅读(369) | 评论 (0)编辑 收藏

先看看 shmctl() 

  原型: int shmctl ( int shmqid, int cmd, struct shmid_ds *buf );

  返回:成功为 0 ,   失败 为-1

 

这个特殊的调用和semctl()调用几乎相同,因此,这里不进行详细的讨论。有效命令的值是: 

IPC_STAT :检索一个共享段的shmid_ds结构,把它存到buf参数的地址中。 

IPC_SET :对一个共享段来说,从buf 参数中取值设置shmid_ds结构的ipc_perm域的值。 

IPC_RMID :把一个段标记为删除 


 IPC_RMID 命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在最后一个进程离开这个共享段时。

当一个进程不再需要共享内存段时,它将调用shmdt()系统调用卸载,即本进程不再使用这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的 shm_nattch域的值减1。真正把内核中的共享内存删除还得用shmctl。

posted @ 2013-01-06 13:08 鑫龙 阅读(520) | 评论 (0)编辑 收藏

     摘要: 一.基于文件的通信  1.普通文件(io/mmap)  2.有名管道文件  3.匿名管道  4.Socket二.基于内存的通信  0.一组内核内存的工具    ipcs      ipcs -m&nb...  阅读全文

posted @ 2013-01-06 11:32 鑫龙 阅读(414) | 评论 (0)编辑 收藏

mmap函数是unix/linux下的系统调用。

mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
          mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里(因为并不分配空间所以所映射的文件必须已经具有大小,空文件会产生错误), 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.

posted @ 2013-01-06 10:37 鑫龙 阅读(593) | 评论 (0)编辑 收藏

sigaction/sigqueue是signal/kill的升级版

1.sigqueue与kill:sigqueue可以发送额外参数,kill不可以.

2.sigaction与signal:signal通过sigaction实现,sigaction除与signal一样会屏蔽正在处理的信号,还可以通过指定sa_mask屏蔽指定信号。

3.sigaction与signal: sigaction还可以传送信号相关的更多信息及参数.

4.上述4个函数可以混合使用.

posted @ 2013-01-05 17:19 鑫龙 阅读(343) | 评论 (0)编辑 收藏

     摘要: 回顾:  1.信号的作用  2.理解信号:     软中断     可靠与不可靠信号kill -l  3.信号发送与注册kill/raise alarm  setitimer  signal  4.信...  阅读全文

posted @ 2013-01-05 16:03 鑫龙 阅读(425) | 评论 (0)编辑 收藏

转发请注明出处:http://www.cppblog.com/mysileng/admin/EditPosts.aspx?postid=196971
    刚写了程序发现点问题。假设一个程序有多个线程,有一个全局互斥锁M....在某线程A获得锁以后,这个时候来了一个信号(假设这个信号注册了自己的处理程序),那么需要进入信号处理程序,进入以后信号处理处理程序也要获得这个锁。问题来了?会死锁么?
    我们知道同一线程如果重复申请同一个互斥锁那么必然会死锁?这里问题转换到信号处理函数跟之前的线程A会是同一个线程上下文么(即是同一个线程么)?我们试验一下。实验之前需要明确几点:
    1.根据APUE 12.8,进程的处理函数与处理方式是进程中所有线程共享的。
    2.根据APUE 12.8,如果进程接收到信号,该信号只会被递送到某一个单独线程。一般情况下由那个线程引起信号则递送到那个线程。如果没有线程引发信号,信号被发送到任意线程。



     上面程序首先共享了一个共同的SIGUSR1信号处理函数,主控线程A然后产生一个线程B,线程B首先获得全局互斥锁,然后运行一个长5秒的程序,然后释放锁。在B运行了大概2秒的时候,线程A给本进程(注意是进程,而不是某线程)发送一个SIGUSR1信号。此时,会死锁么?编译运行看结果.

    连续运行了5次,都没有死锁。我们分析一下,当进程接收信号时,进程把信号并没有递送给线程B(因为没有产生死锁),也就是说是不是这个递送过程被优化了?还是我们真的运气好?需要进一步探查。接下来我们指定把信号递送给线程B,看会不会死锁。

    接下来编译运行:

    不出意料,果然死锁了。
    也就是说,关于线程与信号处理函数获得同一把互斥锁的问题,关键是看信号被递送给了那个线程,如果信号是被递送给了获得锁的那个线程,就会死锁,如果不是之前获得锁的线程,程序就继续运行。

posted @ 2013-01-05 13:46 鑫龙 阅读(1895) | 评论 (0)编辑 收藏

原文地址:http://blogold.chinaunix.net/u1/48788/showart.php?id=2270724


早期的信号,也就是前32位的信号,在处理信号时,不具备阻塞该信号的能力(也就是不支持排队),只能忽略,这时候就可能丢失信号。
使用不可靠信号时注意:
1) 不要在中断函数中执行过于复杂的处理流程;
2) 在信号处理过程返回前,进程会对相同信号的标志进行屏蔽;
3) 父进程会把当前的信号屏蔽标志位信息传递给它派生的子进程。
 
 
 

信号本质

信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。

信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。

信号来源

信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源,最常用发送信号的系统函数是kill, raise, alarm和setitimer以及sigqueue函数,软件来源还包括一些非法运算等操作。

二、信号的种类

可以从两个不同的分类角度对信号进行分类:(1)可靠性方面:可靠信号与不可靠信号;(2)与时间的关系上:实时信号与非实时信号。在《Linux环境进程间通信(一):管道及有名管道》的附1中列出了系统所支持的所有信号。

1、可靠信号与不可靠信号

"不可靠信号"

Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:

  • 进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。
  • 信号可能丢失,后面将对此详细阐述。
    因此,早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。

Linux支持不可靠信号,但是对不可靠信号机制做了改进:在调用完信号处理函数后,不必重新调用该信号的安装函数(信号安装函数是在可靠机制上的实现)。因此,Linux下的不可靠信号问题主要指的是信号可能丢失。

"可靠信号"

随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。所以,后来出现的各种Unix版本分别在这方面进行了研究,力图实现"可靠信号"。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。同时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction()。POSIX.4对可靠信号机制做了标准化。但是,POSIX只对可靠信号机制应具有的功能以及信号机制的对外接口做了标准化,对信号机制的实现没有作具体的规定。

信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。Linux在支持新版本的信号安装函数sigation()以及信号发送函数sigqueue()的同时,仍然支持早期的signal()信号安装函数,支持信号发送函数kill()。

注:不要有这样的误解:由sigqueue()发送、sigaction安装的信号就是可靠的。事实上,可靠信号是指后来添加的新信号(信号值位于SIGRTMIN及SIGRTMAX之间);不可靠信号是信号值小于SIGRTMIN的信号。信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关。目前linux中的signal()是通过sigation()函数实现的,因此,即使通过signal()安装的信号,在信号处理函数的结尾也不必再调用一次信号安装函数。同时,由signal()安装的实时信号支持排队,同样不会丢失。

对于目前linux的两个信号安装函数:signal()及sigaction()来说,它们都不能把SIGRTMIN以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数(对所有信号这一点都成立),而经过signal安装的信号却不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。

2、实时信号与非实时信号

早期Unix系统只定义了32种信号,Ret hat7.2支持64种信号,编号0-63(SIGRTMIN=31,SIGRTMAX=63),将来可能进一步增加,这需要得到内核的支持。前32种信号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的缺省动作。如按键盘的CTRL ^C时,会产生SIGINT信号,对该信号的默认反应就是进程终止。后32个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。实时信号是POSIX标准的一部分,可用于应用进程。

非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。

posted @ 2013-01-05 11:45 鑫龙 阅读(309) | 评论 (0)编辑 收藏

     摘要: 问题解答:  1.exit(状态码)返回状态码有什么意义?   返回值被系统得到.系统根据状态码进行日志记录.   返回值被调用者得到:system/wait.程序会根据返回状态码进行对应处理。   exit(状态码)=main函数中的return 状态码;  &nbs...  阅读全文

posted @ 2013-01-04 10:42 鑫龙 阅读(617) | 评论 (0)编辑 收藏

首先看一下man的scandir 接口定义
int scandir(const char *dir, struct dirent ***namelist,
              int(*filter)(const struct dirent *),
              int(*compar)(const struct dirent **, const struct dirent **));
,从定义来看就不是一个简单的函数,形参里,出现一个三级指针,二个函数指针。它的功能是,扫描名字为dir的目录,把满足filter函数的过滤条件(即filter执行为非0值)的目录项加入到一维指针数组namelist.数组的总长度为返回值n,如果compar不为空,则最终输出结果还要调用qsort来对数组进行排序后再输出。
 
从scandir的演示代码,我们可以推算出namelist是一个指向一维指针数组的指针。(一维指针数组等同于 struct dirent ** namelist,这里写在三级指针是因为要从函数里改变namelist的值,必须再多做一级)原因可以参考我的函数传值类型的说明。
 
以下是一个简单扫描 /usr/lib,并且把所有以lib打头的文件扫描到namelist数组的测试程序,这是参考scandir 提供的样例来修改,alphasort是做原始的ASCII码值比较进行排序的
 
可以看到namelist是完全动态分配的,不仅数组本身是动态分配,而且数组项指向的空间也是动态分配的。
 
 

#include <sys/types.h>
#include <dirent.h>

#include <sys/stat.h>
#include <unistd.h>

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

//扫描所有的lib打头的文件

 int filter_fn(const struct dirent * ent)
 {
   if(ent->d_type != DT_REG)
     return 0;
     
   return (strncmp(ent->d_name,"lib",3) == 0);
 }


void scan_lib(char * dir_name)
{
  int n;
   struct dirent **namelist; // struct dirent * namelist[];

   n = scandir(dir_name, &namelist, filter_fn, alphasort);
   if (< 0)
        perror("scandir");
   else {
               while(n--) {
                   printf("%s\n", namelist[n]->d_name);
                   free(namelist[n]);
               }
               free(namelist);
           }
}

int main(int argc ,char * argv[])
{
   scan_lib("/usr/lib"); 
}


posted @ 2013-01-02 11:48 鑫龙 阅读(3192) | 评论 (0)编辑 收藏

仅列出标题
共20页: First 5 6 7 8 9 10 11 12 13 Last