Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

read收数据时会导致线程一直执行 #64

Open
zt449569708 opened this issue Oct 22, 2021 · 3 comments
Open

read收数据时会导致线程一直执行 #64

zt449569708 opened this issue Oct 22, 2021 · 3 comments

Comments

@zt449569708
Copy link

问题:
TCP通信,当使用单独的线程去收数据时,并且线程里只使用read函数,不使用select函数配合,代码如下:

 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是否有数,如果有,再释放一次信号量即可

环境:
RT-Thread Studio 2.1.2
wiznet latest

@xiangxistu
Copy link
Collaborator

这个思路挺好的(^_^),可以修改看看效果;好使的话,可以提交一份 PR 。

@BernardXiong
Copy link

这个在底层是lwIP时应该不存在吧?

@zt449569708
Copy link
Author

这个在底层是lwIP时应该不存在吧?

lwip就不清楚了,因为我现在只用了wiznet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants