C 如何同步以下场景
这是我尝试做的一个小例子。现在,您将看到,如果您运行这个,这个示例需要10秒多一点的时间才能完成。这应该不到2秒钟。问题是存在一个竞争条件。循环时间太长,并且在WaitForSingle对象获取它之前发生SetEvent。如果事件可以触发,但WaitForSingleObject仍然可以知道它是以某种方式触发的,那就更好了。 这里发生的事情是生成的数据可能需要很长时间。然后通过网络发送这些数据,这可能需要更长的时间。因此,我想对要发送的数据进行排队,然后在另一个线程拾取数据并将其发送出去时,以我的方式进行处理。这样我就可以无限地排队,直到我无事可做,然后线程加入发送线程,直到它完成所有网络数据的发送C 如何同步以下场景,c,winapi,synchronization,C,Winapi,Synchronization,这是我尝试做的一个小例子。现在,您将看到,如果您运行这个,这个示例需要10秒多一点的时间才能完成。这应该不到2秒钟。问题是存在一个竞争条件。循环时间太长,并且在WaitForSingle对象获取它之前发生SetEvent。如果事件可以触发,但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;
}
#包括
#包括
#包括
#定义管道名称“\\.\\PIPE\\testpipe”
无效复制协议缓冲区(结构协议缓冲区*输入,结构协议缓冲区*输出);
DWORD PipeClientStartSendBufferThread(结构客户端管道设置*管道设置,LPDWORD lpThreadId);
DWORD InitializeClientPipeSettings(结构客户端管道设置*管道设置);
无效初始化协议缓冲区(结构协议缓冲区*协议缓冲区);
结构协议缓冲区{
尺寸与长度;
尺寸和位置;
int数据类型;
字符*数据;
结构协议缓冲区*next;
};
结构客户端\u管道\u设置{
处理高压管道;
LPCTSTR名称;
DWORD管道超时;
处理write_事件;
结构协议缓冲区*fifo;
处理发送线程;
};
DWORD WINAPI PipeClientSendThread(LPVOID客户端\管道\设置\对象){
结构客户端管道设置*管道设置=(结构客户端管道设置*)客户端管道设置对象;
结构协议缓冲区*buf=NULL;
而(1){
WaitForSingleObject(管道设置->写入事件,10000);
如果(buf==NULL){
buf=管道设置->先进先出;
}否则{
结构协议缓冲区*fifo协议缓冲区=buf->next;
免费(buf);
buf=fifo_协议_缓冲区;
如果(buf->length==0)
//退出信号
返回0;
}
//通过网络发送数据
睡眠(500);
}
返回0;
}
DWORD PipeQueueBuffer(结构客户端管道设置*管道设置,结构协议缓冲*buf)
{
结构协议缓冲区*输出协议缓冲区=(结构协议缓冲区*)malloc(sizeof*buf);
if(out\u协议\u缓冲区==NULL)
出口(1);
复制协议缓冲区(buf,输出协议缓冲区);
如果(管道设置->fifo==NULL){
管道设置->fifo=输出协议缓冲区;
}
其他的
{
结构协议缓冲区*最后一个协议缓冲区=管道设置->fifo;
while(最后一个协议缓冲区->下一个!=NULL)
{
last_protocol_buffer=last_protocol_buffer->next;
}
最后一个协议缓冲区->下一个=输出协议缓冲区;
}
如果(!SetEvent(管道设置->写入事件))
返回GetLastError();
返回错误\成功;
}
内部主(空){
结构客户端管道设置管道设置;
初始化客户端管道设置(&pipe_设置);
DWORD dwThreadId=0;
PipeClientStartSendBufferThread(管道设置和dwThreadId);
//生成可能需要一段时间的数据
睡眠(1000);
结构协议缓冲区buf;
初始化\u协议\u缓冲区(&buf);
buf.长度=5;
buf.data=(char*)malloc(5);
基本数据[0]=“b”;
基本数据[1]=“l”;
基本数据[2]=“a”;
buf.数据[3]='h';
基本数据[4]='\0';
管道队列缓冲区(&pipe_设置,&buf);
睡眠(100);
管道队列缓冲区(&pipe_设置,&buf);
buf.length=0;
管道队列缓冲区(&pipe_设置,&buf);
WaitForSingleObject(管道设置.发送线程,100000);
}
DWORD InitializeClientPipeSettings(结构客户端管道设置*管道设置)
{
管道设置->写入事件=CreateEvent(NULL,0,0,NULL);
如果(管道设置->写入事件==NULL)
返回GetLastError();
管道设置->hPipe=无效的管道句柄值;
管道设置->fifo=NULL;
管道设置->发送线程=NULL;
返回错误\成功;
}
DWORD PipeClientStartSendBufferThread(结构客户端管道设置*管道设置,LPDWORD lpThreadId)
{
HANDLE h=CreateThread(NULL,0,PipeClientSendThread,管道设置,0,lpThreadId);
if(h==NULL)
返回GetLastError();
管道设置->发送线程=h;
返回错误\成功;
}
无效复制协议缓冲区(结构协议缓冲区*输入,结构协议缓冲区*输出){
输出->数据类型=输入->数据类型;
输出->长度=输入->长度;
输出->位置=输入->位置;
输出->下一步=输入->下一步;
输出->数据=(字符*)malloc(输入->长度);
如果(输出->数据==NULL){
出口(1);
}
memcpy(out->data,in->data,in->length);
}
无效初始化协议缓冲区(结构协议缓冲区*协议缓冲区)
{
协议缓冲区->数据=NULL;
协议缓冲区->长度=0;
协议缓冲区->位置=0;
协议缓冲区->下一步=空;
协议缓冲区->数据类型=0;
}
您的机制完全错误。它不是关于一个提前到来的事件
如果设置了该事件,则可能会“多次”设置该事件。PipeClientSendThread应该等待事件,如果设置了该事件,它应该发送到达队列的所有元素。将3个元素编码到队列中,但事件设置一次,线程运行并一次只发送一个元素,而下一个元素仅在达到超时时发送
你也有一个大问题。您的队列必须受到关键部分或互斥锁的保护。当另一个线程也在读取和修改队列时,您可以修改并循环队列中的元素
使用crtical节和std::queue。。。这也将帮助您摆脱无内存/malloc的东西。在这个例子中,我忘记了做一件事