Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何同步以下场景_C_Winapi_Synchronization - Fatal编程技术网

C 如何同步以下场景

C 如何同步以下场景,c,winapi,synchronization,C,Winapi,Synchronization,这是我尝试做的一个小例子。现在,您将看到,如果您运行这个,这个示例需要10秒多一点的时间才能完成。这应该不到2秒钟。问题是存在一个竞争条件。循环时间太长,并且在WaitForSingle对象获取它之前发生SetEvent。如果事件可以触发,但WaitForSingleObject仍然可以知道它是以某种方式触发的,那就更好了。 这里发生的事情是生成的数据可能需要很长时间。然后通过网络发送这些数据,这可能需要更长的时间。因此,我想对要发送的数据进行排队,然后在另一个线程拾取数据并将其发送出去时,以我

这是我尝试做的一个小例子。现在,您将看到,如果您运行这个,这个示例需要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的东西。

在这个例子中,我忘记了做一件事