私はコンピュータ上のシリアルポートを読み取り、このデータを周波数スペクトルに変換するためにfftを実行する、ある種のオシロスコープエスクプログラムを作成しています。私はSerialHandler
クラス(boost::Asio
を利用しています)、FFTHandler
クラス、およびmain
の関数に分割された私のプログラムのレイアウトで問題に遭遇しました。 SerialHandler
クラスは、boost::Asio`` async_read_some
関数を使用してポートから読み取り、HandleOnPortReceive
というイベントを発生させ、データ自体を読み取ります。C++セマフォの混乱?
問題は、別のスレッドのio_service
オブジェクトによって生成されたイベントハンドラからそのデータを、別のスレッドのFFTHandler
クラスに渡す方法が見つからないことでした。私は問題を解決するためにセマフォを使用することが推奨されましたが、私はsemaphore.hの使用法に関する知識がないので、実装は今やかなり壊れていて、それは想定していたものをほとんど行いません。
それはそれは少し明確になります場合はここにいくつかのコードです:
using namespace Foo;
//main function
int main(void){
SerialHandler serialHandler;
FFTHandler fftHandler;
sem_t *qSem_ptr = &qSem;
sem_init(qSem_ptr, 1, 0);
//create separate threads for both the io_service and the AppendIn so that neither will block the user input statement following
serialHandler.StartConnection(tempInt, tempString); //these args are defined, but for brevity's sake, I ommitted the declaration
t2= new boost::thread(boost::bind(&FFTHandler::AppendIn, &fftHandler, q, qSem));
//allow the user to stop the program and avoid the problem of an infinite loop blocking the program
char inChar = getchar();
if (inChar) {...some logic to stop reading}
}
namespace Foo{
boost::thread *t1;
boost::thread *t2;
sem_t qSem;
std::queue<double> q;
boost::mutex mutex_;
class SerialHandler{
private:
char *rawBuffer; //array to hold incoming data
boost::asio::io_service ioService;
boost::asio::serial_port_ptr serialPort;
public:
void SerialHandler::StartConnection(int _baudRate, string _comPort){
//some functionality to open the port that is irrelevant to the question goes here
AsyncReadSome(); //starts the read loop
//create thread for io_service object and let function go out of scope
t1 = new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
void SerialHandler::AsyncReadSome(){
//there's some other stuff here for error_catching, but this is the only important part
serialPort->async_read_some (
boost::asio::buffer(rawBuffer, SERIAL_PORT_READ_BUF_SIZE),
boost::bind(
&SerialHandler::HandlePortOnReceive,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, q));
}
void SerialHandler::HandlePortOnReceive(const boost::system::error_code& error, size_t bytes_transferred, std::queue<double>& q){
boost::mutex::scoped_lock lock(mutex_);
//more error checking goes here, but I've made sure they aren't returning and are not the issue
for (unsigned int i =0; i<bytes_transferred; i++){
unsigned char c = rawBuffer[i];
double d = (double) c; //loop through buffer and read
if (c==endOfLineChar){
} else //if not delimiting char, push into queue and post semaphore
{
q.push(d);
//cout << d << endl;
sem_post(&qSem);
cout << q.front() << endl;
cout << "size is: " << q.size() << endl;
}
}
//loop back on itself and start the next read
AsyncReadSome();
}
}
class FFTHandler{
private:
double *in; //array to hold inputs
fftw_complex *out; //holds outputs
int currentIndex;
bool filled;
const int N;
public:
void AppendIn(std::queue<double> &q, sem_t &qSem){
while(1){ //this is supposed to stop thread from exiting and going out of scope...it doesn't do that at all effectively...
cout << "test" << endl;
sem_wait(&_qSem); //wait for data...this is blocking but I don't know why
double d = _q.front();
_q.pop();
in[currentIndex]=d; //read queue, pop, then append in array
currentIndex++;
if (currentIndex == N){ //run FFT if full and reset index
currentIndex = N-overlap-1;
filled = true;
RunFFT();
}
}
}
}
}
FFTHandler::AppendIn(..)
でのデバッグ行が実際に発射され、そのスレッドが作成されているが、それはimmediateleyスコープ外になるだろうそれはそうと破壊こと私はセマフォに間違って応答するように設定しているようだからです。
TLDR:。それは今、私はうまくいけば、このコードのヘルプを受信するためにここに来て、私が試した、失敗した、単に私がセマフォを理解何とかそれらを実装する必要はありません」、と言うのに長い説明でした私よりも精通して誰かから
UPDATE:だから、いくつかのデバッグ文で遊んでた後、それは問題がwhile(1){...}
文が実際に発射され、しかし、sem_wait(&_qSem);
はそれをブロックする原因になっているということのようです何のために。セマフォがポストされているにもかかわらず、無期限に待機している理由は、待ち続けており、その行を超えて進んでいることはありません。
_semaphore usage_に間違ったものは何も見えませんが、スレッディングの潜在的な問題を見ることができます - スレッドが終了する前に 'main'が終了していますか? (ちょうど "...いくつかのロジックが読み込みを停止する"というコードからはっきりしていません) –
なぜSerialHandlerとFFTHandlerを別々のスレッドで実行していますか? SerialHandlerが次のデータセットを受け取れるように別のスレッドに作業を渡すことが意図されている場合は、Leader/Followersパターンを考慮し、スレッドのプールにio_serviceを実行させます。ここでは、各スレッドはSerialHandlerを使用してデータを読み込み、FFTHandlerを使用してデータを処理し、終了するとプールに戻り、次のioイベントを待機します。 – aichao
@aichao私はハンドラ内でループバックするため、別のスレッドで実行しているSerialHandler io_serviceを持っています。したがって、無限ループが作成されます。しかし、私はプログラムを止めることができたいと思っています。無限ループはまったく望ましい機能ではありませんでしたので、ユーザーの入力を受け入れるために別のスレッドに移動しました。同様の理由から、 'FFTHandler :: AppendIn(...)'関数は、メインスレッドをブロックせず、プログラムの実行中にユーザーがプログラムを実行できるようにする(つまりプログラムを停止する)ために、 。 – Scorch