[英]How to synchronize the following scenario
这是我正在尝试做的一个最小的例子。 现在您将看到,如果您运行它,则该示例需要 10 多秒才能完成。 应该不到 2 秒。 问题是存在竞争条件。 循环花费的时间太长,并且 SetEvent 发生在 WaitForSingle 对象可以获取它之前。 如果事件可以触发但 WaitForSingleObject 仍然可以知道它以某种方式触发,那就太好了。 这里发生的情况是生成的数据可能需要很长时间。 然后该数据通过网络发送,这可能需要更长的时间。 所以我想将要发送的数据排队,然后在另一个线程获取数据并将其发送出去时以我的快乐方式。 这样我就可以无限排队,直到我无事可做,然后线程加入发送线程,直到它完成发送所有网络数据。
#include <stdio.h>
#include <windows.h>
#include <unistd.h>
#define PIPE_NAME "\\\\.\\pipe\\testpipe"
void copy_protocol_buffer(struct protocol_buffer *in, struct protocol_buffer *out);
DWORD PipeClientStartSendBufferThread(struct client_pipe_settings *pipe_settings, LPDWORD lpThreadId);
DWORD InitializeClientPipeSettings(struct client_pipe_settings *pipe_settings);
void initialize_protocol_buffer(struct protocol_buffer *protocol_buffer);
struct protocol_buffer {
size_t length;
size_t location;
int data_type;
char *data;
struct protocol_buffer *next;
};
struct client_pipe_settings {
HANDLE hPipe;
LPCTSTR name;
DWORD pipe_timeout;
HANDLE write_event;
struct protocol_buffer *fifo;
HANDLE send_thread;
};
DWORD WINAPI PipeClientSendThread(LPVOID client_pipe_settings_object) {
struct client_pipe_settings *pipe_settings = (struct client_pipe_settings *)client_pipe_settings_object;
struct protocol_buffer *buf = NULL;
while(1) {
WaitForSingleObject(pipe_settings->write_event, 10000);
if (buf == NULL) {
buf = pipe_settings->fifo;
} else {
struct protocol_buffer *fifo_protocol_buffer = buf->next;
free(buf);
buf = fifo_protocol_buffer;
if(buf->length == 0)
//signal to quit
return 0;
}
//Send data over the network
Sleep(500);
}
return 0;
}
DWORD PipeQueueBuffer(struct client_pipe_settings *pipe_settings, struct protocol_buffer *buf)
{
struct protocol_buffer *out_protocol_buffer = (struct protocol_buffer *)malloc(sizeof *buf);
if(out_protocol_buffer == NULL)
exit(1);
copy_protocol_buffer(buf, out_protocol_buffer);
if (pipe_settings->fifo == NULL) {
pipe_settings->fifo = out_protocol_buffer;
}
else
{
struct protocol_buffer *last_protocol_buffer = pipe_settings->fifo;
while(last_protocol_buffer->next != NULL)
{
last_protocol_buffer = last_protocol_buffer->next;
}
last_protocol_buffer->next = out_protocol_buffer;
}
if(!SetEvent(pipe_settings->write_event))
return GetLastError();
return ERROR_SUCCESS;
}
int main(void) {
struct client_pipe_settings pipe_settings;
InitializeClientPipeSettings(&pipe_settings);
DWORD dwThreadId = 0;
PipeClientStartSendBufferThread(&pipe_settings, &dwThreadId);
//Generate data which could take a while
Sleep(1000);
struct protocol_buffer buf;
initialize_protocol_buffer(&buf);
buf.length = 5;
buf.data = (char *)malloc(5);
buf.data[0] = 'b';
buf.data[1] = 'l';
buf.data[2] = 'a';
buf.data[3] = 'h';
buf.data[4] = '\0';
PipeQueueBuffer(&pipe_settings, &buf);
Sleep(100);
PipeQueueBuffer(&pipe_settings, &buf);
buf.length = 0;
PipeQueueBuffer(&pipe_settings, &buf);
WaitForSingleObject(pipe_settings.send_thread, 100000);
}
DWORD InitializeClientPipeSettings(struct client_pipe_settings *pipe_settings)
{
pipe_settings->write_event = CreateEvent(NULL, 0, 0, NULL);
if(pipe_settings->write_event == NULL)
return GetLastError();
pipe_settings->hPipe = INVALID_HANDLE_VALUE;
pipe_settings->fifo = NULL;
pipe_settings->send_thread = NULL;
return ERROR_SUCCESS;
}
DWORD PipeClientStartSendBufferThread(struct client_pipe_settings *pipe_settings, LPDWORD lpThreadId)
{
HANDLE h = CreateThread(NULL, 0, PipeClientSendThread, pipe_settings, 0, lpThreadId);
if(h == NULL)
return GetLastError();
pipe_settings->send_thread = h;
return ERROR_SUCCESS;
}
void copy_protocol_buffer(struct protocol_buffer *in, struct protocol_buffer *out) {
out->data_type = in->data_type;
out->length = in->length;
out->location = in->location;
out->next = in->next;
out->data = (char*)malloc(in->length);
if (out->data == NULL) {
exit(1);
}
memcpy(out->data, in->data, in->length);
}
void initialize_protocol_buffer(struct protocol_buffer *protocol_buffer)
{
protocol_buffer->data = NULL;
protocol_buffer->length = 0;
protocol_buffer->location = 0;
protocol_buffer->next = NULL;
protocol_buffer->data_type = 0;
}
你的机制是错误的。 它不是关于提前出现的 SetEvent。
如果事件被设置,它可能被设置为“不止一次”。 PipeClientSendThread 应该等待事件,如果事件被设置,它应该发送所有已经到达队列的元素。 您将 3 个元素编码到队列中,但事件设置一次,线程运行并一次仅发送一个元素,而下一个元素仅在达到超时时发送....
你还有一个很大的问题。 您的队列必须受临界区或互斥锁保护。 您修改和循环队列中的元素,而另一个线程也在读取和修改队列。
使用关键部分和 std::queue ......这也将帮助您摆脱内存空闲/malloc 的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.