#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
коде, эти данные должны быть защищены, например, мьютексом.