C++ 客户端上的Grpc访问冲突

C++ 客户端上的Grpc访问冲突,c++,c++17,visual-studio-2019,grpc,access-violation,C++,C++17,Visual Studio 2019,Grpc,Access Violation,我正在玩弄GRPC。目前,我使用C#web应用程序作为我的GRPC服务器,使用C++控制台应用程序作为客户端 我能够成功地连接并与服务器通信,没有任何问题。问题出现在 我退出C++控制台客户端应用程序。退出时,将抛出访问冲突 堆栈跟踪 MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::thread_body MeterReaderClientCpp.exe!__acrt_lock ntdll.dll

我正在玩弄
GRPC
。目前,我使用
C#
web应用程序作为我的
GRPC
服务器,使用
C++
控制台应用程序作为客户端

我能够成功地连接并与服务器通信,没有任何问题。问题出现在 我退出
C++
控制台客户端应用程序。退出时,将抛出访问冲突

堆栈跟踪

MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::thread_body  
MeterReaderClientCpp.exe!__acrt_lock
ntdll.dll!RtlpWaitOnCriticalSection()
ntdll.dll!RtlpEnterCriticalSectionContended()
ntdll.dll!RtlEnterCriticalSection()
MeterReaderClientCpp.exe!__acrt_lock(__acrt_lock_id _Lock) Line 55
MeterReaderClientCpp.exe!_free_dbg(void * block, int block_use) Line 1019
MeterReaderClientCpp.exe!free(void * block) Line 32
MeterReaderClientCpp.exe!gpr_free(void * p) Line 53
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::destroy_thread() Line 142
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::Join() Line 112
MeterReaderClientCpp.exe!grpc_core::Thread::Join() Line 147
MeterReaderClientCpp.exe!gc_completed_threads() Line 74
MeterReaderClientCpp.exe!stop_threads() Line 331
MeterReaderClientCpp.exe!grpc_timer_manager_set_threading(bool threaded) Line 351
MeterReaderClientCpp.exe!grpc_shutdown_internal_locked() Line 175
MeterReaderClientCpp.exe!grpc_shutdown_internal(void * __formal) Line 208
MeterReaderClientCpp.exe!`anonymous namespace'::ThreadInternalsWindows::thread_body(void * v) Line 128
GRPC客户端

int main( )
{
    using namespace MeterReaderWeb::Services;
    using namespace google::protobuf::util;
    using namespace google::protobuf;


    std::cout << "Press enter\n";
    std::cin.ignore( );

    std::cout << "Calling Grpc service\n";

    std::fstream file{ R"(C:\Certificates\certificate.cer)", std::ios::in | std::ios::beg };
    if ( !file.is_open( ) )
    {
        std::cerr << "Failed to open file\n";
        return 1;
    }

    std::stringstream buffer;
    buffer << file.rdbuf( );

    grpc::SslCredentialsOptions options;
    options.pem_root_certs = buffer.str( );

    auto credentials{ grpc::SslCredentials( options ) };
    auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
    auto stub{ MeterReadingService::NewStub( channel ) };

    ReadingPacket packet;
    packet.set_status( ReadingStatus::METER_READER_SUCCESS );
    packet.set_notes( "Here are some random notes" );

    auto message{ packet.add_readings( ) };    
    message->set_customer_id( 1 );
    message->set_reading_value( 10001 );

    auto timestamp{ message->mutable_reading_time( ) };
    timestamp->CopyFrom( TimeUtil::GetCurrentTime( ) );

    grpc::ClientContext context;
    StatusMessage response;
    if ( auto status{ stub->AddReading( &context, packet, &response ) }; status.ok( ) )
    {
        std::cout << "Added reading successfully\n";
        auto responseStatus{ response.status( ) };
        if ( responseStatus == ReadingStatus::METER_READER_SUCCESS )
        {
            std::cout << "Server status: success\n" 
                      << "Message: " << response.message( ) << '\n';

        }
    }
    else
    {
        std::cerr << "Error: " << status.error_message( ) << '\n';
        std::cerr << "Error Details: " << status.error_details( ) << '\n';
    }

    std::cin.ignore( );
}
int main( )
{
    std::cout << "Press enter\n";
    std::cin.ignore( );

    std::cout << "Calling Grpc service\n";
    grpc_init( );

    { // <- Intentionally added scope here.

        grpc::SslCredentialsOptions options;

        if ( auto certificate{ ReadCertificate( ) } )
            options.pem_root_certs = std::move( certificate ).value( );
        else return 1;

        auto credentials{ grpc::SslCredentials( options ) };
        auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
        auto stub{ MeterReadingService::NewStub( channel ) };

        std::cout << "Sending single packet\n";
        SendPacket( stub.get( ), 8000 );

        std::cout << "Sending multiple packets\n";
        StreamDiagnostics( stub.get( ), 3 );
    }

    std::cout << "Shutting down library\n";
    grpc_shutdown_blocking( );
    std::cout << "Shut down complete press enter to exit\n";
    std::cin.ignore( );
}
int main()
{
使用命名空间MeterReaderWeb::Services;
使用名称空间google::protobuf::util;
使用名称空间google::protobuf;
std::coutcopyFrom(TimeUtil::GetCurrentTime());
grpc::ClientContext;
状态消息响应;
if(自动状态{stub->AddReading(&context,packet,&response)};status.ok())
{

std::cout好的,我相信我已经找到了导致问题的原因

在我最初的帖子中,我说:

我已经尝试向
grpc\u init()
grpc\u shutdown()
添加调用,尽管 客户端示例不包含这两个调用 加上这些都没有效果。”

这是真的,但在重新阅读
grpc\u shutdown()
的文档后,我注意到了这一点(我的重点):

最后一次调用
grpc_shutdown
将启动grpc清理 库内部,这可能发生在另一个线程中 已完成清理,grpc未使用内存,也未使用任何指令 在grpc库中执行。调用之前,所有应用程序 拥有的grpc对象必须已销毁。

这就是我认为我出错的地方。我调用了
grpc\u shutdown()
,而我的作用域中仍然有grpc对象。为了更正,我对grpc
对象的作用域进行了限定,然后在退出该作用域后调用了
grpc\u shutdown()
。这似乎纠正了问题

新Grpc客户端

int main( )
{
    using namespace MeterReaderWeb::Services;
    using namespace google::protobuf::util;
    using namespace google::protobuf;


    std::cout << "Press enter\n";
    std::cin.ignore( );

    std::cout << "Calling Grpc service\n";

    std::fstream file{ R"(C:\Certificates\certificate.cer)", std::ios::in | std::ios::beg };
    if ( !file.is_open( ) )
    {
        std::cerr << "Failed to open file\n";
        return 1;
    }

    std::stringstream buffer;
    buffer << file.rdbuf( );

    grpc::SslCredentialsOptions options;
    options.pem_root_certs = buffer.str( );

    auto credentials{ grpc::SslCredentials( options ) };
    auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
    auto stub{ MeterReadingService::NewStub( channel ) };

    ReadingPacket packet;
    packet.set_status( ReadingStatus::METER_READER_SUCCESS );
    packet.set_notes( "Here are some random notes" );

    auto message{ packet.add_readings( ) };    
    message->set_customer_id( 1 );
    message->set_reading_value( 10001 );

    auto timestamp{ message->mutable_reading_time( ) };
    timestamp->CopyFrom( TimeUtil::GetCurrentTime( ) );

    grpc::ClientContext context;
    StatusMessage response;
    if ( auto status{ stub->AddReading( &context, packet, &response ) }; status.ok( ) )
    {
        std::cout << "Added reading successfully\n";
        auto responseStatus{ response.status( ) };
        if ( responseStatus == ReadingStatus::METER_READER_SUCCESS )
        {
            std::cout << "Server status: success\n" 
                      << "Message: " << response.message( ) << '\n';

        }
    }
    else
    {
        std::cerr << "Error: " << status.error_message( ) << '\n';
        std::cerr << "Error Details: " << status.error_details( ) << '\n';
    }

    std::cin.ignore( );
}
int main( )
{
    std::cout << "Press enter\n";
    std::cin.ignore( );

    std::cout << "Calling Grpc service\n";
    grpc_init( );

    { // <- Intentionally added scope here.

        grpc::SslCredentialsOptions options;

        if ( auto certificate{ ReadCertificate( ) } )
            options.pem_root_certs = std::move( certificate ).value( );
        else return 1;

        auto credentials{ grpc::SslCredentials( options ) };
        auto channel{ grpc::CreateChannel( "localhost:5001", credentials ) };
        auto stub{ MeterReadingService::NewStub( channel ) };

        std::cout << "Sending single packet\n";
        SendPacket( stub.get( ), 8000 );

        std::cout << "Sending multiple packets\n";
        StreamDiagnostics( stub.get( ), 3 );
    }

    std::cout << "Shutting down library\n";
    grpc_shutdown_blocking( );
    std::cout << "Shut down complete press enter to exit\n";
    std::cin.ignore( );
}
int main()
{
标准::cout