我这里有线程问题吗?
我最近在玩GNU Radio,发现了一个叫tunnel.py的程序。这个程序可以让你通过无线电链接在Linux的TUN/TAP设备上隧道传输IP流量。大部分功能都正常,但有一部分代码让我感到困惑。
里面有一个类实现了“基本的MAC层”。这个类有一个回调函数,用来向TUN设备写入新的数据包。这个函数(phy_rx_callback
)是从一个单独的线程中调用的。
函数main_loop
在发送新数据包之前会先进行载波侦测。我不明白的是,为什么在一个不重叠的发送通道上发送之前,还要侦测接收通道。
接收(RX)和发送(TX)通道是不同的频率,我们的硬件支持全双工通信。
所以,我的问题是,当main_loop
在执行时,另一个线程异步调用phy_rx_callback
函数会有什么影响?我想搞清楚载波侦测循环的目的,我发现如果把那段代码注释掉,性能会大幅下降。我觉得在使用发送通道之前监测接收通道没有道理,这样就变成了半双工通信。我也不明白为什么要使用两个频率,一个用于发送,一个用于接收。我开始怀疑这里是不是有奇怪的线程问题。
最开始只创建了一个cs_mac
类的实例。一个指向rx_callback函数的“指针”被传递到线程类中,实际上是由它来调用这个函数。以下是cs_mac类的代码:
class cs_mac(object):
def __init__(self, tun_fd, verbose=False):
self.tun_fd = tun_fd # file descriptor for TUN/TAP interface
self.verbose = verbose
self.tb = None # top block (access to PHY)
def set_top_block(self, tb):
self.tb = tb
def phy_rx_callback(self, ok, payload):
if self.verbose:
print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload))
if ok:
os.write(self.tun_fd, payload)
def main_loop(self):
min_delay = 0.001 # seconds
while 1:
payload = os.read(self.tun_fd, 10*1024)
if not payload:
self.tb.send_pkt(eof=True)
break
if self.verbose:
print "Tx: len(payload) = %4d" % (len(payload),)
delay = min_delay
while self.tb.carrier_sensed():
sys.stderr.write('B')
time.sleep(delay)
if delay < 0.050:
delay = delay * 2 # exponential back-off
self.tb.send_pkt(payload)
好吧,我使用ctypes.CDLL('libc.so.6').syscall(186)
,也就是调用gettid
,发现调用rx_callback
函数的线程有相同的PID,但不同的TID。
问题是,另一个线程从主线程中调用一个对象的函数(而且那个线程还在不断循环)会有什么影响?
1 个回答
main_loop这个函数在发送新数据包之前会先检查一下信号。让我困惑的是,为什么在一个不重叠的发送信道上发送之前,还要检查接收信道。
CSMA/CA这个技术是用在半双工系统里的,也就是说所有的设备在发送和接收时都用同一个频率。所以你说得对,如果你在不同的信道上发送,那检查接收信道就没什么意义了。
carrier_sensed()这个函数是在receive_path.py文件中调用的,所以它应该是在接收线程里运行。在我的代码中,我把sys.stderr.write('B')和time.sleep(delay)这两行注释掉了,结果似乎没有影响性能。可能我的情况有点不同,因为我使用的是一个半双工的XCVR扩展板。