while (1)
{
ret = read(sock, buf, 64);
if (ret <= 0)
{
break;
}
rt_ringbuffer_put(rx_ring_buf, buf, ret);
}
如果此时对方只发了一次数据,那么线程会一直执行,不会阻塞,导致低优先级线程无法调度。
原因是wiz_recvfrom函数里面有这样一段代码,
uint16_t recvsize = getSn_RX_RSR(socket);
/* receive last transmission of remaining data */
if (recvsize > 0)
{
rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
recv_len = wizchip_recv(socket, mem, len);
if (recv_len > 0)
{
rt_mutex_release(sock->recv_lock);
goto __exit;
}
rt_mutex_release(sock->recv_lock);
}
if (socket_state == SOCK_CLOSED)
{
return 0;
}
else if (socket_state != SOCK_ESTABLISHED)
{
LOG_E("WIZnet receive failed, get socket(%d) register state(%d) error.", socket, socket_state);
result = -1;
goto __exit;
}
while (1)
{
/* wait the receive semaphore */
if (rt_sem_take(sock->recv_notice, timeout) < 0)
{
result = -1;
/* blocking mode will prints an error and non-blocking mode exits directly */
if ((flags & MSG_DONTWAIT) == 0)
{
LOG_E("WIZnet socket (%d) receive timeout (%d)!", socket, timeout);
errno = EAGAIN;
}
goto __exit;
}
else
{
if (sock->state == SOCK_ESTABLISHED)
{
/* get receive buffer to receiver ring buffer */
rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);
recv_len = wizchip_recv(socket, mem, len);
if (recv_len < 0)
{
LOG_E("WIZnet socket(%d) receive data failed(%d).", socket, recv_len);
rt_mutex_release(sock->recv_lock);
result = -1;
goto __exit;
}
rt_mutex_release(sock->recv_lock);
}
else if (sock->state == SOCK_CLOSED)
{
result = 0;
goto __exit;
}
break;
}
}
break;
}
这段代码先通过getSn_RX_RSR判断是否有数据,有的话就返回,这就导致第二次read时,getSn_RX_RSR判断到无数据,就到下面的 if (rt_sem_take(sock->recv_notice, timeout) < 0)这,因为这里信号量已经在中断里面释放过了,所以这里是不会阻塞的,从而进入到wizchip_recv函数,而这个函数里面就一直在判断getSn_RX_RSR是否有数,因为对端只发了一次,第一次已经读走了,因此getSn_RX_RSR一直返回0,从而形成无阻赛的死循环。
所以wiz_recvfrom函数应该改进,通过注释(/ receive last transmission of remaining data /)可以看出,是否防止数据读不干净,而这样做的。那么为啥不在wizchip_recv执行完后,再去判断getSn_RX_RSR是否有数,如果有,再释放一次信号量即可
问题: TCP通信,当使用单独的线程去收数据时,并且线程里只使用read函数,不使用select函数配合,代码如下:
如果此时对方只发了一次数据,那么线程会一直执行,不会阻塞,导致低优先级线程无法调度。
原因是wiz_recvfrom函数里面有这样一段代码,
这段代码先通过getSn_RX_RSR判断是否有数据,有的话就返回,这就导致第二次read时,getSn_RX_RSR判断到无数据,就到下面的 if (rt_sem_take(sock->recv_notice, timeout) < 0)这,因为这里信号量已经在中断里面释放过了,所以这里是不会阻塞的,从而进入到wizchip_recv函数,而这个函数里面就一直在判断getSn_RX_RSR是否有数,因为对端只发了一次,第一次已经读走了,因此getSn_RX_RSR一直返回0,从而形成无阻赛的死循环。
所以wiz_recvfrom函数应该改进,通过注释(/ receive last transmission of remaining data /)可以看出,是否防止数据读不干净,而这样做的。那么为啥不在wizchip_recv执行完后,再去判断getSn_RX_RSR是否有数,如果有,再释放一次信号量即可
环境: RT-Thread Studio 2.1.2 wiznet latest