Ниже приведен пример программного обеспечения одного из возможных способов «отфильтровать» повторяющиеся пробелы из входного потока.
Идея опирается на использование двух потоков.
Thrd1 читает из потока строк с именем ssIn. (Заменяется на cin в вашем коде.)
Thrd1 (фильтр) обнаруживает и сбрасывает последовательные пробелы и отправляет только первый (из нескольких пробелов) в thrd2.
Thrd2 - читает из единственного буфера символов, заполненного thrd1, который никогда не увидит символы пробела.
2 трети синхронизируются парой семафоров (не мьютекс).
В моем примере для моего удобства я использовал свою версию семафора Posix. Я не знаю, есть ли у вас Posix, но я уверен, что вы легко найдете множество примеров семафоров C ++, доступных в Интернете, даже в SO, и большинство из которых использует только функции C ++.
Обратите внимание, что это всего лишь 1 тест ... алфавит с 1 000 000 пробелов, вставленных после 'j'. Это не проверка через. Там, вероятно, будут другие вопросы, чтобы иметь дело с. Я установил жесткую обработку неправильного поведения ввода. Утверждение поможет вам определить проблемы.
"thrd2" представляет вашу привязку к этому примеру. Thrd2 получает отфильтрованный поток.
#include "../../bag/src/dtb_chrono.hh"
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
using std::chrono::duration_cast;
#include <iostream>
using std::cout, std::flush, std::endl;
//using std::cin;
#include <thread>
using std::thread, std::this_thread::sleep_for;
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
// Posix Process Semaphore, local mode, unnamed, unlocked
#ifndef DTB_PPLSEM_HH
#include "../../bag/src/dtb_pplsem.hh"
using DTB::PPLSem_t;
#endif
// string ops
#ifndef DTB_SOPS_HH
#include "../../bag/src/dtb_sops.hh"
using DTB::SOps_t;
#endif
#include <cassert>
namespace DTB
{
class T946_t
{
public:
int operator()(int argc, char* argv[]) // functor entry
{ return exec(argc, argv); }
private:
// uses compiler provided default ctor and dtor
// Posix Process Semaphore, local mode (unnamed, unshared)
// initial value unlocked
PPLSem_t th1Sem;
PPLSem_t th2Sem;
char kar = '\n';
bool done = false;
size_t m_rdy;
thread* th1;
string th1Log;
thread* th2;
string th2Log;
stringstream ssIn; // debug - replaces cin
stringstream ss1DR; // th1 delay'd report
stringstream ss2DR; // th2 delay'd report
// utilities
SOps_t sops; // string ops - digiComma
int exec(int , char** )
{
// test init: insert a possible user input into ssIn
init_ssIn();
int retVal = 0;
Time_t start_ns = HRClk_t::now();
th1Sem.lock(); // block until threads are ready
th2Sem.lock(); // block
// start ---------vvvvvvvvvvvvvvvvvvv
th1 = new thread(&T946_t::thrd1, this);
assert(nullptr != th1);
while (0 == (m_rdy & 0x01))
std::this_thread::sleep_for(10ms);
// start ---------vvvvvvvvvvvvvvvvvv
th2 = new thread(&T946_t::thrd2, this);
assert(nullptr != th2);
while (0 == (m_rdy & 0x02))
std::this_thread::sleep_for(10ms);
th1Sem.unlock();
// spin wait for threads to complete
while (!done)
{
std::this_thread::sleep_for(100ms);
}
th1->join();
th2->join();
cout << "\n join()'s complete";
auto duration_ns = duration_cast<NS_t>(HRClk_t::now() - start_ns).count();
cout << "\n T901_t::exec() duration "
<< sops.digiComma(duration_ns) << " ns" << endl;
// output the delay'd reports
cout << ss1DR.str() << ss2DR.str() << endl;
return retVal;
}
void init_ssIn()
{
ssIn << "abcdefghij";
for (int i=0; i<1000001; ++i) ssIn << ' ';
std::string::size_type k = ssIn.str().size();
ssIn << "klmnopqrstuvwxyz";
// a..j
cout << "\n ssIn: '" << ssIn.str().substr(0, 10)
<< " ...spaces... " << ssIn.str().substr(k, 16) << "'"
<< "\n ssIn.str().size(): "
<< sops.digiComma(ssIn.str().size()) << endl;
}
void thrd1()
{
uint64_t th1Count = 0;
uint64_t th1Skips = 0;
char lkar = '\0';
m_rdy |= 0x01; // sync msg to main
do {
getNextKar(lkar); // read from input (ssIn or cin)
th1Sem.lock(); // wait for thrd2 to give permission
{
if(' ' == lkar) // current input kar
{
if(' ' == kar) // previous kar
{
// filter out back-to-back space chars
th1Skips += 1;
th1Sem.unlock(); // skip the handshake, no char to send,
// give self permission-to-proceed
continue;
}
}
// else, not a duplicate space
th1Count += 1;
kar = lkar; // write to input of thrd2
th1Log += lkar; // log
lkar = ' ';
}
th2Sem.unlock(); // give thrd2 permission-to-proceed
if (ssIn.eof())
{
done = true;
break;
}
}while(!done);
ss1DR
<< "\n th1Count " << sops.digiComma(th1Count)
<< "\n th1Skips " << sops.digiComma(th1Skips)
<< "\n th1Log " << th1Log
<< "\n thrd1 exit " << endl;
}
// read from ssIn for development
// read from cin for app
void getNextKar(char& lkar)
{
// ssIn >> lkar; // reads 1 char, but skips multiple blank chars
// lkar = ssIn.get(); returns an integer (not a char)
(void)ssIn.get (lkar);
if(ssIn.fail())
{
if(ssIn.eof()) return; // not a fail
assert(0); // harsh exit, might want something gentler
}
}
void thrd2()
{
uint64_t th2Count = 0;
m_rdy |= 0x02; // sync msg to main
do {
th2Sem.lock(); // wait for thrd1 to give permission
char t = kar;
th1Sem.unlock(); // give permission-to-proceed to thrd1
// simulate application - no duplicate spaces from input
th2Log += t;
th2Count += 1;
// end of sim
}while(!done);
ss2DR
<< "\n th2Count " << sops.digiComma(th2Count)
<< "\n th2Log " << th2Log
<< "\n thrd2 exit " << endl;
}
}; // class T946_t
} // namespace DTB
int main(int argc, char* argv[]) { return DTB::T946_t()(argc, argv); }
Вывод выглядит так:
ssIn: 'abcdefghij ...spaces... klmnopqrstuvwxyz'
ssIn.str().size(): 1,000,027
join()'s complete
T901_t::exec() duration 120,421,582 ns
th1Count 28
th1Skips 1,000,000
th1Log abcdefghij klmnopqrstuvwxyz
thrd1 exit
th2Count 28
th2Log abcdefghij klmnopqrstuvwxyz
thrd2 exit
Продолжительность 120 мс при вводе 1 млн символов.