『壹』 关于linux signal的问题
也就是说,当GPS数据准备好后会发送signal给你们自己写的平台软件,相当于请求刷屏幕,然后平台软件执行刷屏幕操作,这两个之间需要一个同步关系就是说,当有请求后我才去刷屏幕操作。
这种情况不是因为平台进程接受不到signal,而是收到了signal信号而且正确执行了sem_post操作(你可以在signal handler中加入打印调试语句看看),因为你的刷屏幕操作线程执行时间太长了,导致连续执行好几次屏幕操作,这是种恶性循环(因为gps软件每次数据准备好就发送个signal,而你的 signal在每次捕捉到signal后就执行一次sem_post,然而你的刷屏幕操作时间太长了当执行完一次刷屏幕操作后再次调用sem_wait的时候已经有多个信号量资源了也就是消费跟不上生产,信号量post次数比wait次数多)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
sem_t lock;
int gps_data = 0;
/* fflush screen thread */
void *gps_data_process (void *arg)
{
while (1)
{
/* wait gps data is ready */
/* second run sem_wait will by more semaphore it will not block */
sem_wait(&lock);
/* ok data is ready */
printf("Data is [%d]\n", gps_data);
/* simulate a long procees time */
sleep(100);
}
}
/* SIGUSR1 handler */
void gps_data_request(int sig)
{
if (sig == SIGUSR1)
{
/* ok gps data is ready so request process */
sem_post(&lock);
}
}
int main(int argc, char **argv)
{
pthread_t tid;
struct sigaction action;
/* initialize semaphore */
if (sem_init(&lock, 0, 0) == -1)
{
perror("sem_init");
exit(1);
}
action.sa_handler = gps_data_request;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
/* caught signal SIGUSR1 */
if (sigaction(SIGUSR1, &action, NULL))
{
perror("sigaction");
exit(1);
}
/* create a thread */
if (pthread_create(&tid, NULL, gps_data_process, NULL) == -1)
{
perror("pthread_create");
exit(1);
}
while (1)
{
printf("[GPS]>>>");
/* gps get data ready */
scanf("%d", &gps_data);
if (gps_data)
{
/* simulate gps program send signal to platform process */
raise(SIGUSR1);
}
sleep(1);
}
return 0;
}
『贰』 Linux环境下使用signal函数进行进程间通信的问题
测试了一下,三个进程都会收到SIGINT信号。
原程序中,child1, child2都收到SIGINT信号,调用stop(), 之后被唤醒,打印"child process ... is killed by parent!",事实上kill这两个child的不是parent,是它们自己的SIGINT。
放到①处,child1收到SIGINT信号,默认的行为是把自己杀了,当然也来不及打印任何东西了。child2收到SIGINT信号,打断waiting(),打印"child process 2 ...",然后退出。杀死它的也不是SIGUSR2信号。
放到②处,child1, child2收到SIGINT信号,默认的行为是立即把自己杀了,也来不及打印任何东西了。
测试方法:
// 打印谁执行、被什么信号打断
static void stop(int signal) {
printf("stop %d by signal %d\n", getpid(), signal);
wait_mark=0;
}
// 在parent进程中,打印各进程id
printf("parent %d, child1 %d, child2 %d\n",getpid(),p1,p2);
如果让parent成为杀死child的凶手,可以在child1,child2中加入:
signal(SIGINT, keep_me_alive);
// 不理睬SIGINT信号
static void keep_me_alive(int signal) {
}
这时打印结果就一样了
『叁』 Linux信号量
信号量是包含一个非负整数型的变量,并且带有两个原子操作wait和signal。Wait还可以被称为down、P或lock,signal还可以被称为up、V、unlock或post。在UNIX的API中(POSIX标准)用的是wait和post。
对于wait操作,如果信号量的非负整形变量S大于0,wait就将其减1,如果S等于0,wait就将调用线程阻塞;对于post操作,如果有线程在信号量上阻塞(此时S等于0),post就会解除对某个等待线程的阻塞,使其从wait中返回,如果没有线程阻塞在信号量上,post就将S加1.
由此可见,S可以被理解为一种资源的数量,信号量即是通过控制这种资源的分配来实现互斥和同步的。如果把S设为1,那么信号量即可使多线程并发运行。另外,信号量不仅允许使用者申请和释放资源,而且还允许使用者创造资源,这就赋予了信号量实现同步的功能。可见信号量的功能要比互斥量丰富许多。
POSIX信号量是一个sem_t类型的变量,但POSIX有两种信号量的实现机制: 无名信号量 和 命名信号量 。无名信号量只可以在共享内存的情况下,比如实现进程中各个线程之间的互斥和同步,因此无名信号量也被称作基于内存的信号量;命名信号量通常用于不共享内存的情况下,比如进程间通信。
同时,在创建信号量时,根据信号量取值的不同,POSIX信号量还可以分为:
下面是POSIX信号量函数接口:
信号量的函数都以sem_开头,线程中使用的基本信号函数有4个,他们都声明在头文件semaphore.h中,该头文件定义了用于信号量操作的sem_t类型:
【sem_init函数】:
该函数用于创建信号量,原型如下:
该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示信号量是当前进程的局部信号量,否则信号量就可以在多个进程间共享,value为sem的初始值。
该函数调用成功返回0,失败返回-1。
【sem_destroy函数】:
该函数用于对用完的信号量进行清理,其原型如下:
成功返回0,失败返回-1。
【sem_wait函数】:
该函数用于以原子操作的方式将信号量的值减1。原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。其原型如下:
sem指向的对象是sem_init调用初始化的信号量。调用成功返回0,失败返回-1。
sem_trywait()则是sem_wait()的非阻塞版本,当条件不满足时(信号量为0时),该函数直接返回EAGAIN错误而不会阻塞等待。
sem_timedwait()功能与sem_wait()类似,只是在指定的abs_timeout时间内等待,超过时间则直接返回ETIMEDOUT错误。
【sem_post函数】:
该函数用于以原子操作的方式将信号量的值加1,其原型如下:
与sem_wait一样,sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1。
【sem_getvalue函数】:
该函数返回当前信号量的值,通过restrict输出参数返回。如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。
【实例1】:
【实例2】:
之所以称为命名信号量,是因为它有一个名字、一个用户ID、一个组ID和权限。这些是提供给不共享内存的那些进程使用命名信号量的接口。命名信号量的名字是一个遵守路径名构造规则的字符串。
【sem_open函数】:
该函数用于创建或打开一个命名信号量,其原型如下:
参数name是一个标识信号量的字符串。参数oflag用来确定是创建信号量还是连接已有的信号量。
oflag的参数可以为0,O_CREAT或O_EXCL:如果为0,表示打开一个已存在的信号量;如果为O_CREAT,表示如果信号量不存在就创建一个信号量,如果存在则打开被返回,此时mode和value都需要指定;如果为O_CREAT|O_EXCL,表示如果信号量存在则返回错误。
mode参数用于创建信号量时指定信号量的权限位,和open函数一样,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。
value表示创建信号量时,信号量的初始值。
【sem_close函数】:
该函数用于关闭命名信号量:
单个程序可以用sem_close函数关闭命名信号量,但是这样做并不能将信号量从系统中删除,因为命名信号量在单个程序执行之外是具有持久性的。当进程调用_exit、exit、exec或从main返回时,进程打开的命名信号量同样会被关闭。
【sem_unlink函数】:
sem_unlink函数用于在所有进程关闭了命名信号量之后,将信号量从系统中删除:
【信号量操作函数】:
与无名信号量一样,操作信号量的函数如下:
命名信号量是随内核持续的。当命名信号量创建后,即使当前没有进程打开某个信号量,它的值依然保持,直到内核重新自举或调用sem_unlink()删除该信号量。
无名信号量的持续性要根据信号量在内存中的位置确定:
很多时候信号量、互斥量和条件变量都可以在某种应用中使用,那这三者的差异有哪些呢?下面列出了这三者之间的差异:
『肆』 fork(),signal(),kill(),wait()这几个命令是c函数还是linux操作系统的系统调用
你可以这么理解:
这几个都是linux系统编程中的函数,C语言写的;当然他也是系统调用接口;他们并不冲突;你自己写个程序调用这些接口也是可以的; APUE中有介绍这几个函数;