2010-10-15 131 views
1

我正在寻找关于重入的一些信息,然后我遇到了关于信号和线程的信息。两者有什么区别?信号与线程

请指教。

非常感谢。

回答

4

您正在比较苹果和橘子。 Signal Programming是事件驱动编程,可用于影响线程。然而,信号编程范例可以用于单线程应用程序。

+0

@sasayins:这是本书的开始,你正在考虑* nix。 – yadab 2010-10-15 11:16:57

1

要理解信号,最好从思考单线程程序开始。这个程序正在对它的一个线程做任何事情,然后将信号传递给它。如果程序为该信号注册了一个信号处理程序(一个调用函数),那么在调用信号处理程序函数时,该程序的正常执行将暂停一点点(非常类似于硬件中断会中断操作系统运行中断服务程序)并运行程序已经注册的功能来处理该信号。因此,与代码:

#include <stdio.h> 
#include <signal.h> 
#include <unistd.h> // for alarm 

volatile int x = 0; 

void foo(int sig_num) { 
    x = sig_num; 
} 

int main(void) { 
    unsigned long long count = 0; 
    signal(SIGALRM, foo); 
    alarm(1); // This is a posix function and may not be in all hosted 
       // C implementations. 
       // SIGALRM will be sent to this process in 1 second. 
    while (!x) { 
     printf("not x\n"); 
     count++; 
    } 
    printf("x is %i and count = %llu\n", x, count); 
} 

该程序将循环,直到有人给它发送一个信号(这种情况如何可能会因平台而有所不同)。如果发送信号SIGINT,则foo将设置为x并且循环将退出。确切地说foo被调用的循环中的位置并不清楚。它可能发生在打印和递增计数之间,恰好在条件被测试之后,在打印期间......很多地方,真的。这就是为什么信号可能带来并发或重入问题 - 它们可以在事先没有其他代码知道它发生的情况下改变它们。

x被声明为volatile的原因是没有那么多编译器可能会认为“嘿,没有人在主要更改x和main不会调用任何其他函数,所以x永远不会更改”并优化循环测试。指定volatile告诉C编译器,这个变量可以被看不见的力(例如信号处理程序,其他线程,或者有时甚至是内存映射设备控制寄存器的硬件)改变。

这是很容易,以确保x被看出来妥善两个信号处理程序和主代码执行之间因为x就是一个整数(加载和存储它很可能是一个指示组件中的每个),这是只是在这种情况下被的东西(信号处理程序,而不是主代码)所改变,并且它仅被用作简单的布尔值。如果x是某种其他类型(如字符串),则由于信号可能随时中断您的信号处理程序可能会覆盖部分字符串,而主代码正在读取字符串。当你在刷牙时,有人会冻结时间,用眼镜蛇取代你的牙刷,然后解冻时间,这可能会有结果。

有关信号的更多信息 - 它们是C语言的一部分,但它们的大部分用途并未被C覆盖。许多与信号有关的Linux,Unix和POSIX函数都不是是C语言的一部分,但很难拿出合理的(和小的)信号使用的例子,它不依赖于C标准以外的东西,这就是我使用alarm函数的原因。作为C的一部分的raise函数可以用来向自己发送信号,但是要示例更难。

当信号看起来像现在一样可怕时,大多数系统都有更多的功能,使它们更容易使用。

线程,最后

线程同时执行,而信号中断。虽然有一些线程库实际上以这种方式实现线程,但事实并非如此,最好是用这种方式来思考线程。由于计算机程序的能力实际上非常有限,因此它们能够看到线程可以像对待信号处理程序一样阻碍主执行代码(可能比信号处理程序更频繁)。

想象一下,你即将再次刷牙,但这次你是清醒和盲目的。现在你的室友,也是高清和盲人,进来用一些硅胶封口剂固定水槽。就像你拿到牙膏一样,他把硅胶管放在牙膏管的顶部,然后你拿起硅胶管而不是牙膏。请记住,既然你既是盲人又是高级(并且不会碰到对方),你们都假设没有其他人在使用水槽,所以你永远不会意识到你刚把牙刷上的硅胶放在你的牙刷上,要意识到他正在试图用牙膏填满瓷砖和水槽背面之间的裂缝。

幸运的是,有线程可以互相沟通,以便某些东西当前正在使用,所以其他线程应该远离(比如在刷牙时锁定门)。