C x向服务器发送数据以在GUI上显示输出的线程数

C x向服务器发送数据以在GUI上显示输出的线程数,c,windows,multithreading,winapi,tcp,C,Windows,Multithreading,Winapi,Tcp,我开发了一个单服务器/多客户端TCP应用程序 客户端由x个线程组成,每个线程对自己的数据进行处理,然后通过TCP套接字将数据发送到服务器进行显示 服务器基本上是一个有窗口的GUI。服务器从客户端接收数据并显示它 现在的问题是,由于客户端中有40个线程,每个线程都想发送数据,如何使用一个连接的套接字来实现这一点 我的建议: 我的方法是在40个线程中的每个线程中创建一个数据结构,将在其中维护要发送的数据。然后在客户端创建一个单独的发送线程和一个连接的套接字。这个线程将从第一个线程的数据结构中读取数据

我开发了一个单服务器/多客户端TCP应用程序

客户端由x个线程组成,每个线程对自己的数据进行处理,然后通过TCP套接字将数据发送到服务器进行显示

服务器基本上是一个有窗口的GUI。服务器从客户端接收数据并显示它

现在的问题是,由于客户端中有40个线程,每个线程都想发送数据,如何使用一个连接的套接字来实现这一点

我的建议:

我的方法是在40个线程中的每个线程中创建一个数据结构,将在其中维护要发送的数据。然后在客户端创建一个单独的发送线程和一个连接的套接字。这个线程将从第一个线程的数据结构中读取数据,通过套接字发送数据,然后从第二个线程读取数据,依此类推

困惑:

但我不确定这将如何实施,因为我对这一切都不熟悉:(如果一个线程正在写入数据结构,而发送线程试图同时读取数据,该怎么办?我熟悉互斥、临界区等,但对于我的简单应用程序来说,这听起来太复杂了

欢迎提出我个人建议以外的任何其他建议/意见。 如果你认为我自己的方法是正确的,那么请帮助我解决我上面提到的困惑

提前多谢:)

编辑:


我是否可以将I定时器置于发送线程上,并在特定时间后发送线程挂起线程#1(以便它可以访问其数据结构而无需任何同步问题),从其数据结构读取数据,通过tcp套接字发送数据,然后恢复线程#1,然后挂起线程#2,从其数据结构读取数据,通过tcp套接字发送数据,然后恢复线程#2返回,依此类推。

常用的方法是使用一个专用于发送数据的线程。其他线程将其数据发布到一个共享容器(list、deque等)中,并向发送者线程发出数据可用的信号。然后,发送者醒来并处理任何可用的数据

编辑:

其要点如下:

HANDLE data_available_event; // manual reset event; set when queue has data, clear when queue is empty
CRITICAL_SECTION cs; // protect access to data queue
std::deque<std::string> data_to_send;

WorkerThread()
{
    while(do_work)
    {
        std::string data = generate_data()
        EnterCriticalSection(&cs);
        data_to_send.push_back(data);
        SetEvent(data_available_event); // signal sender thread that data is available
        LeaveCriticalSection(&cs);
    }
}

SenderThread()
{
    while(do_work)
    {
        WaitForSingleObject(data_available_event);
        EnterCriticalSection(&cs);
        std::string data = data_to_send.front();
        data_to_send.pop_front();
        if(data_to_send.empty())
        {
            ResetEvent(data_available_event); // queue is empty; reset event and wait until more data is available
        }
        LeaveCriticalSection(&cs);
        send_data(data);
    }
}
处理数据\u可用\u事件;//手动复位事件;当队列有数据时设置,当队列为空时清除
临界截面cs;//保护对数据队列的访问
std::确定要发送的数据;
WorkerThread()
{
(工作时)
{
std::string data=generate_data()
肠危重科(&cs);
数据发送。向后推(数据);
SetEvent(data_available_event);//向发送器线程发送数据可用的信号
离开关键部门(&cs);
}
}
SenderThread()
{
(工作时)
{
WaitForSingleObject(数据可用事件);
肠危重科(&cs);
std::string data=data_to_send.front();
数据发送到发送。弹出前端();
if(数据发送到发送.空())
{
ResetEvent(data_available_event);//队列为空;重置事件并等待更多数据可用
}
离开关键部门(&cs);
发送_数据(数据);
}
}

这当然是假设数据可以以任何顺序发送。我使用字符串只是为了说明的目的;您可能需要某种自定义对象,它知道如何序列化它所持有的数据。

有几种方法可以实现它;卢克的想法受到种族条件的影响,这仍然会造成数据损坏

通过使用UDP而不是TCP作为传输协议,可以避免这种情况。如果您不介意偶尔丢失一个数据包(用于显示快速变化的数据),那么它将是一个特别好的选择;在准确的历史记录无关紧要的情况下(在绘制图形时,在相对平滑的曲线中缺少一点是可以的),它可以确保数据的实时更新

如果数据包很小并且某种程度上代表一个流,那么UDP是一个很好的选择。如果在不同的系统上有多个发送器,并且所有发送器都显示在一个屏幕上,那么它的好处就会增加。

挂起线程#1以便访问它的数据结构不会避免同步问题。当您挂起它时,线程#1可能正在更新数据,因此套接字线程获取部分旧数据,部分新数据。这就是数据损坏

您需要一个共享数据结构,如FIFO队列。工作线程添加到队列中,套接字线程从队列中删除最旧的项。除非实现无锁队列,否则必须使用关键部分保护对此共享队列的所有访问。(一个循环缓冲区。)


根据应用程序的需要,如果实现此队列,可能根本不需要套接字线程。只需在显示线程中退出队列。

+1对于帖子来说,这看起来是个好主意,但问题是我的40个线程都处于while(1)循环中,不断生成数据发送到服务器进行显示,因此我不知道所有40个线程何时将数据写入共享内存。请参阅我刚才添加的编辑。您可以使用关键部分保护对容器的访问。非常感谢您的编辑。看起来真的很有帮助。但对于将其转换为x工作线程,我并不感到困惑。当工作线程1已经完成了价格处理,现在正在写入关键部分,同时线程2尝试这样做时会发生什么。线程2发出的对关键部分的请求是否会排队,并且一旦线程1释放了关键部分,它就会被发送到线程2?是的,EnterCriticalSections()会阻止其他线程,直到拥有关键部分的线程调用LeaveCriticalSection()。调用EnterCriticalSection()时,然后对所有全局变量的访问被限制在进入Critical Section的线程中,或者只有我们想要保护的变量属于Critical Section?如果您