[Mac M2 Pro 12CPU, Sonoma 14.3.1, clang++ 15.0.0, FLTK 1.3.8]
中断ボタンでlibcurlによるHTTP通信をabortしようとしましたが、かなり手こずりました。
C++では難しいためSwiftへの移植も考えたものの、相当な時間を掛けることになるのでもう一粘りしたところ、あっさり解決しました。
CURL* curl = curl_easy_init();のcurlをグローバル変数にして、中断コールバック関数内でcurl_easy_cleanup(curl);とすれば中断できるようになりました。
シングルスレッドであるFLTKにて送信ボタン押下状態で中断ボタンを押せるようにするにはstd::threadを用い送信コールバック関数(HTTP通信)を別スレッド化する必要があります。
最初は別スレッド化したHTTP通信のプロセスID(PID)をpgrepコマンドで探し、killコマンドで中断しようとしました。しかしstd::threadでは同じプロセスIDをメインスレッドと共用しているため、その方法は使えませんでした。
昨年2023/3/2にChatGPTアプリ開発に着手してから、ずっと抱えていた懸案をようやく解決できました。
libcurlでHTTP通信が容易に中断できない問題はStackOverFlowサイトでも暗礁に乗り上げていたので意外な結末でした。ChatGPTに聞いてもサンプルコードが少ないためか、珍しく迷回答頻発でした。
#include <thread>
#include <future>
#include <curl/curl.h>
extern CURL* curl;
void sendCBWrapper(Fl_Widget* w, void* v) {
// promiseとfutureを作成
std::promise<void> p;
std::future<void> f = p.get_future();
// sendCBを新しいスレッドで実行し、promiseを渡す
std::thread([w, v, p = std::move(p)]() mutable {
sendCB(w, v, std::move(p));
}).detach();
// 別のスレッドでfutureの結果を待機
std::thread([f = std::move(f)]() mutable {
f.wait(); // sendCBの終了を待機
std::system("afplay /System/Library/Sounds/Submarine.aiff"); // システム音を鳴らす
cout << "sendCB終了" << endl;
}).detach();
}
void abortCB(Fl_Widget*, void*){
if (curl){
curl_easy_cleanup(curl);
statusBox -> changeColor(YELLOW);
} else {
cout << "送信していません" << endl;
}
}