Как мне экспортировать символ метода c и exec из оболочки?

#c

#c

Вопрос:

я понимаю, что, используя extern "C" , я могу вызвать метод c из программы на c, потому что стратегия искажения имен отличается.

Теперь я хочу вызвать метод c из оболочки, но я не знаю как?

Например, у меня есть некоторый код, подобный приведенному ниже:

 extern "C" void Print_Statistic(){
    // output some data to console
}

int main() {
    // something works
    return 0;
}
 

И пока программа запущена, я хотел бы подключиться к ее процессу и вызвать Print_Statistic() из командной строки оболочки, чтобы я мог распечатать некоторые данные на консоли.
я действительно не знаю, как это сделать.

Комментарии:

1. Оболочки не работают таким образом, они могут выполнять только программы (которые вызывают main функцию).

2. @Someprogrammerdude: оболочки могут отправлять сигналы запущенным программам. Сигнал завершения является обычным явлением, но HUP часто используется, чтобы сообщить запущенной программе, что ей необходимо перезагрузить конфигурацию.

3. Я вижу два варианта: 1. считывать команды из стандартного ввода (т.Е. std::cin ). Затем ваша оболочка может передавать в нее команды. 2. укажите аргументы командной строки вашей программы, чтобы включить / отключить параметры для ее выполнения. ( LeanCpp.com : Аргументы командной строки )

4. @MSalters Но это все равно не то же самое, что «вызывать» произвольную функцию.

Ответ №1:

Предполагая, что оболочка posxy, вам нужно будет вызвать void Print_Statistic() из signal обработчика. Затем вы устанавливаете флаг напоминания для печати этих статистических данных. Внутри обработчика сигналов вы не можете печатать. Сигнал понятия не имеет, может ли целевая программа печатать что-либо одновременно!

Как вы проверите этот флаг напоминания из вашего другого кода, зависит от вас; это вопрос дизайна более высокого уровня.

Ответ №2:

Если вы хотите запустить a print_statistics() из командной строки, вам нужна дополнительная программа, которая выполняет запуск. Этот триггер должен работать между процессами; ваша дополнительная программа — это один процесс, а ваша исходная программа — другой процесс. Кроме std::filesystem того, стандартный C не обеспечивает межпроцессного взаимодействия и, к сожалению, для вас, std::filesystem не очень подходит для ваших целей. Итак, вам нужно решение, зависящее от операционной системы, и предпочтительно решение, которое работает довольно одинаково для разных операционных систем. Ниже я включил некоторый код, предназначенный как для Linux, так и для Windows.

Ваша исходная программа:

 #include <sstream>
#include <future>
#include <thread>
#include <chrono>
#include <iostream>

#ifdef __linux__ 

#include <semaphore.h>
#include <fcntl.h>

using event_t = sem_t*;

event_t create_event()
{
    event_t event = sem_open("/print_statistics", O_CREAT, 0644, 0);
    if (event == SEM_FAILED)
    {
        int error = errno;
        std::stringstream ss;
        ss << "sem_open failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    return event;
}

bool wait_for(event_tamp; event)
{
    if (sem_wait(event))
    {
        int error = errno;
        std::stringstream ss;
        ss << "sem_wait failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    return true;
}

void close_event(event_tamp; event) noexcept
{
    sem_close(event);
}

#elif _WIN32

#include <Windows.h>

using event_t = HANDLE;

event_t create_event()
{
    event_t event = CreateEventA(nullptr, FALSE, FALSE, "Local\print_statistics");
    if (!event)
    {
        DWORD error = GetLastError();
        std::stringstream ss;
        ss << "CreateEventA failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    return event;
}

bool wait_for(event_tamp; event)
{
    if( WaitForSingleObject( event, INFINITE) != WAIT_OBJECT_0)
    {
        DWORD error = GetLastError();
        std::stringstream ss;
        ss << "WaitForSingleObject failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    return true;
}

void close_event(event_tamp; event) noexcept
{
    CloseHandle(event);
}

#else
# error "Unsupported OS"
#endif

void print_statistics()
{
    std::cout << "some data" << std::endl;
}

int main() 
{
    try
    {
        auto close_on_exit = [](event_t* p) { close_event(*p); };
        event_t event = create_event();
        std::unique_ptr<event_t, decltype(close_on_exit)> raii_event(amp;event, close_on_exit);

        std::atomic_bool do_continue = true;
        std::future<void> print_statistic_future = std::async(std::launch::async, [amp;do_continue, amp;event]()
            {
                auto make_false_on_exit = [](std::atomic_bool* p) { *p = false; };
                std::unique_ptr<std::atomic_bool, decltype(make_false_on_exit)> raii_do_continue(amp;do_continue, make_false_on_exit);
                while (wait_for(event))
                {
                    print_statistics();
                }
            });
        while (do_continue)
        {
            // something works
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s);
        }
        print_statistic_future.get();
    }
    catch (std::exceptionamp; e)
    {
        std::cerr << e.what() << std::endl;
    }
}
 

Дополнительная программа для запуска триггера:

 #include <sstream>
#include <iostream>

#ifdef __linux__ 

#include <semaphore.h>

void trigger_event()
{
    sem_t* event = sem_open("/print_statistics", 0);
    if (event == SEM_FAILED)
    {
        int error = errno;
        std::stringstream ss;
        ss << "sem_open failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    if (sem_post(event))
    {
        int error = errno;
        sem_close(event);
        std::stringstream ss;
        ss << "sem_post failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    sem_close(event);
}

#elif _WIN32

#include <Windows.h>

void trigger_event()
{
    HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, "Local\print_statistics");
    if (!event)
    {
        DWORD error = GetLastError();
        std::stringstream ss;
        ss << "OpenEventA failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    if (!SetEvent(event))
    {
        DWORD error = GetLastError();
        CloseHandle(event);
        std::stringstream ss;
        ss << "SetEvent failed with error code " << error << ".";
        throw std::runtime_error(ss.str());
    }
    CloseHandle(event);
}

#else
# error "Unsupported OS"
#endif

int main()
{
    try
    {
        trigger_event();
    }
    catch (std::exceptionamp; e)
    {
        std::cerr << e.what() << std::endl;
    }
}
 

Я думаю, дополнительную программу не так сложно прочитать.

Ваша исходная программа стала намного сложнее. Для печати статистики было создано будущее. Это будущее зависает в wait_for(event) вызове до тех пор, пока дополнительная программа не предоставит триггер. Обработка ошибок, установка do_continue логического значения в false и закрытие события еще больше усложняют код. Пожалуйста, обратите внимание, что при print_statistics чтении данных, которые также записаны в // something works коде, эти данные должны быть защищены, например, мьютексом.