How to stop all pthreads when one has completed its work? - c++

I'm trying to create a code to brute-force a random string but running it on one thread makes it take too long (as expected). I'm fiddling around with pthreads and this is what i've come up with:
void*
bruteForce ( void* ARGS )
{
args *arg = ( args * ) ARGS;
string STRING= arg->STRING;
string charSet = arg->charSet;
string guess = arg->guess;
char c;
int size;
int pos;
int lenght;
int j = 0;
char CHAR[STRING.length ( )];
size = charSet.length ( );
do
{
for ( j = 0; j < STRING.length ( ); j++ )
{
pos = rand ( ) % size;
CHAR[j] = charSet[pos];
guess = string ( CHAR );
//cout << guess[j];
}
//cout << guess << endl;
}
while ( STRING!= guess );
}
int
main ( int argc, char** argv )
{
srand ( ( unsigned ) ( time ( NULL ) ) );
const int NUMBER_OF_THREADS = 10;
args arg;
ifstream myFile;
string STRING;
string charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
string guess;
pthread_t threads[NUMBER_OF_THREADS];
void* status;
arg.charSet = charSet;
arg.STRING= STRING;
char c;
int size;
int pos;
int lenght;
int j = 0;
myFile.open ( "string.txt" );
getline ( myFile, STRING);
size = charSet.length ( );
int rc;
//Creating threads for cracking the string
for ( int i = 0; i < NUMBER_OF_THREADS; i++ )
{
rc = pthread_create ( &threads[i], NULL, bruteForce, ( void* ) &arg );
if ( rc )
{
cout << "Couldnt create thread";
exit ( 1 );
}
}
//Joining threads
for ( int i = 0; i < NUMBER_OF_THREADS; i++ )
{
rc = pthread_join ( threads[i], &status );
if ( rc )
{
cout << "thread number " << i << " was unable to join: " << rc << endl;
exit ( 1 );
}
}
}
Now, I need someway of signaling that one of the threads has already guessed the string correctly and terminate the others. I read some of the documentation for pthread library and couldn't find anything. Any help is appreciated.
PS: I know the brute-force algorithm is by far not the best.

As long as you don't want your program to run any longer after the answer is found, you can just call exit(0) from the thread which found the answer.
do
{
// ...
}
while ( STRING!= guess );
std::cout << guess << std::endl;
std::exit(0);

Clumsy but workable in your case:
Add a DONE flag in global scope. Set it when a result is found by any thread.
Make each thread's loop be dependent on the flag.
bool DONE=false; // set to true to stop other threads
void*bruteForce ( void* ARGS )
{ ...
do
{ <try a string>
}
while ( !DONE && STRING!= guess );
DONE=true; // set redundantly but that doesn't hurt
}
Your main program can still do the join to collect finished pthreads, and then continue on with any work it might want to do on the guessed answer.

Related

Strange behavior with char pointer and char pointer returned by fonction in C/C++ with "cout"

I have a strange behavior with a char pointer initialized by the value of a return function and with the cout.
All my code is for an Arduino application, this is why I use char pointer, char array and string.h.
I created a class named FrameManager, with a function getDataFromFrame to extract data from a string (in fact a char array). See above:
`char * FrameManager::getDataFromFrame ( const char frame[], char key[] )
{
char *pValue = nullptr;
int frameLength = strlen ( frame );
int previousStartIndex = 0;
for ( int i=0; i<frameLength; i++ ) {
char c = frame[i];
if ( c == ',' ) {
int buffSize = i-previousStartIndex+1;
char subbuff[buffSize];
memset ( subbuff, 0, buffSize ); //clear buffer
memcpy ( subbuff, &frame[previousStartIndex], i-previousStartIndex );
subbuff[buffSize]='\0';
previousStartIndex = i+1;
int buffLength = strlen ( subbuff );
const char *ptr = strchr ( subbuff, ':' );
if ( ptr ) {
int index = ptr-subbuff;
char buffKey[index+1];
memset ( buffKey, 0, index+1 );
memcpy ( buffKey, &subbuff[0], index );
buffKey[index+1]='\0';
char buffValue[buffLength-index];
memset ( buffValue, 0, buffLength-index );
memcpy ( buffValue, &subbuff[index+1], buffLength-index );
buffValue[buffLength-index]='\0';
if ( strcmp ( key,buffKey ) == 0 ) {
pValue = &buffValue[0];
break;
}
}
} else if ( i+1 == frameLength ) {
int buffSize = i-previousStartIndex+1;
char subbuff[buffSize];
memcpy ( subbuff, &frame[previousStartIndex], frameLength-1 );
subbuff[buffSize]='\0';
int buffLength = strlen ( subbuff );
const char *ptr = strchr ( subbuff, ':' );
if ( ptr ) {
int index = ptr-subbuff;
char buffKey[index+1];
memset ( buffKey, 0, index+1 );
memcpy ( buffKey, &subbuff[0], index );
buffKey[index+1]='\0';
char buffValue[buffLength-index];
memset ( buffValue, 0, buffLength-index );
memcpy ( buffValue, &subbuff[index+1], buffLength-index );
buffValue[buffLength-index]='\0';
if ( strcmp ( key,buffKey ) == 0 ) {
pValue = &buffValue[0];
break;
}
}
}
}
return pValue;
}`
In the main(), I created juste a little code to test the returned value:
int main(int argc, char **argv) {
const char frame[] = "DEVICE:ARM,FUNC:MOVE_F,PARAM:12,SERVO_S:1";
FrameManager frameManager;
char key[] = "DEVICE";
char *value;
value = frameManager.getDataFromFrame(frame, &key[0]);
cout << "Retrieved value: " << value << endl;
cout << "Retrieved value: " << frameManager.getDataFromFrame(frame, &key[0]) << endl;
printf("%s",value);
return 0;
}
and here the result:
Retrieved value: y%R
Retrieved value: ARM
ARM
The first "cout" doesn't display the expected value.
The second "cout" display the expected value and the printf too.
I don't understand what is the problem with the first "cout".
Thanks
Jocelyn
pValue points into local arrays, which get out of scope. That's undefined behavior. It might work, but your program might also crash, return wrong values (that's what you experience), corrupt your data or do any other arbitrary action.
Given that you're already using C++, consider using std::string as a result instead or point into the original frame (if possible).

Can I change data with a std::shared_lock on a std::shared_mutex?

I have multiple buffers being shared with multiple reader/writer threads, and different writers change the data as different manners.
For example, Writer1 merely appends new data, while Writer2 extends the size of buffer(re-alloc memory and move data).
If I put a single mutex to sync all the accesses to the data, the performance maybe not better, because most reader just need to read a single buffer, and most writer just need to write a little piece of data to a single buffer.
If I prepare one mutex for each buffer, the locking/unlocking relationship between threads will be more complicated.
Now I want to confirm a thing:
If a writer change the data only with a shared_lock on the mutex, whether the others would see dirty data with a unique_lock/shared_lock on same mutex?
I coded an experimental program as following, and it looks like no error, but I still dare not use it in product.
atomic_bool g_abShouldRun = true;
sem_t g_semDoIt1;
sem_t g_semDone1;
sem_t g_semDoIt2;
sem_t g_semDone2;
shared_mutex g_mutex;
int g_iX = 3, g_iY = 9, g_iR1 = 1, g_iR2 = 3;
void writer() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt1 );
while( rand() % 8 != 0 )
;
{
shared_lock<shared_mutex> lk( g_mutex );
g_iX *= 2;
g_iY *= 2;
}
sem_post( &g_semDone1 );
};
};
void reader() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt2 );
while( rand() % 8 != 0 )
;
{
unique_lock<shared_mutex> lk( g_mutex );
g_iR1 = g_iX;
g_iR2 = g_iY;
}
sem_post( &g_semDone2 );
};
};
int main( int argc, char** argv ) {
int iLasting = 10, iError = 0;
if( argc > 1 )
iLasting = atoi( argv[1] );
steady_clock::time_point tpEnd = steady_clock::now() + seconds( iLasting );
if( sem_init( &g_semDoIt1, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ||
sem_init( &g_semDoIt2, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ) {
cerr << "Failed to create semaphors." << endl;
return EXIT_FAILURE;
}
thread thd1( writer );
thread thd2( reader );
while( steady_clock::now() < tpEnd ) {
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
sem_wait( &g_semDone1 );
sem_wait( &g_semDone2 );
if( g_iR1 * 3 != g_iR2 )
++iError;
}
g_abShouldRun = false;
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
thd1.join();
thd2.join();
sem_destroy( &g_semDoIt1 );
sem_destroy( &g_semDoIt2 );
sem_destroy( &g_semDone1 );
sem_destroy( &g_semDone2 );
cout << "Error:" << iError << endl;
return EXIT_SUCCESS;
};
The following problems jump out at a quick look:
change the code to use unique_lock when writing;
change the code to use shared_lock when reading;
do not modify other common global variables when reading -- that will practically be writing, just in a different place;
how many { shared_mutexs, function using unique_lock, function using shared_lock } tuples you'll be using with multiple threads and multiple buffers, you'll need to figure out yourself -- but it'll be between 1 and the number of buffers.

Libtorrent Session_Status not updating

Im trying to get Session_Status updated but for whatever reason the values of the structure never update, session is started like so:
using namespace libtorrent;
session* Session;
session_status* Session_Status;
session_settings* Session_Settings;
bool Start_Client_Sess ( )
{
using namespace libtorrent;
Session = new session;
Session_Status = new session_status;
Session_Settings = new session_settings;
Session->settings ( );
Session->set_settings ( *Session_Settings );
Session->add_extension ( create_ut_pex_plugin );
Session->add_extension ( create_ut_metadata_plugin );
Session->add_extension ( create_lt_trackers_plugin );
Session->add_extension ( create_smart_ban_plugin );
Session->start_upnp ( );
Session->start_natpmp ( );
Session->start_dht ( );
Session->start_lsd ( );
error_code e;
Session->listen_on ( std::make_pair ( 6881 , 6889 ) , e );
if ( e )
{
return false;
}
return true;
}
then on a Windows 1 second timer I'm doing this:
void RunTimer ( )
{
using namespace libtorrent;
Session->status ( );
if ( Session->is_listening ( ) )
{
if ( Session_Status->has_incoming_connections )
{
INT x = 2;
std::cout << x << "\n";
}
else
{
INT x = 1;
std::cout << x << "\n";
}
}
else
{
INT x = 0;
std::cout << x << "\n";
}
}
but no matter what the session is always listening even if the firewall is blocking Libtorrent and there is always connections even if the internet is off.
I believe you meant to assign the session status to your Session_Status object:
*Session_Status = Session->status();
I would suggest you don't heap allocate the session_status nor session_settings objects.

Segmentation Fault C++, Linked List

I am going through and comparing a bunch of DNA sequences to find if it is a subset of another. I remove those that are subsets of another.
I'm using a linked list and I keep getting a segmentation fault somewhere around the output of the data back to the output file.
I'd also greatly appreciate feedback on overall code structure. I know its rather messy so I figured someone could point out some things that should be improved on.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
/*
* Step 1. Load all sequences and their metadata into structures.
*
* Step 2. Start n^2 operation to compare sequences.
*
* Step 3. Output file back to a different fasta file.
*/
typedef struct sequence_structure sequence_structure;
struct sequence_structure
{
char *sequence;
char *id;
char *header;
sequence_structure *next_sequence_structure;
sequence_structure *previous_sequence_structure;
int length;
};
int main(int argc, char *argv[])
{
FILE *input_file;
ofstream output_file;
/* this is the TAIL of the linked list. This is a reversed linked list. */
sequence_structure *sequences;
int first_sequence = 0;
char *line = (char*) malloc( sizeof( char ) * 1024 );
if( argc != 3 )
{
printf("This program requires a input file and output file as its argument!\n");
return 0;
}
else
{
/* let's read the input file. */
input_file = fopen( argv[1], "r" );
}
while( !feof(input_file) )
{
string string_line;
fgets( line, 2048, input_file );
string_line = line;
if( string_line.length() <= 2 )
break;
if( string_line.at( 0 ) == '>' )
{
sequence_structure *new_sequence = (sequence_structure *) malloc( sizeof( sequence_structure ) );
new_sequence->id = (char *) malloc( sizeof( char ) * ( 14 + 1 ) );
string_line.copy( new_sequence->id, 14, 1 );
(new_sequence->id)[14] = '\0';
stringstream ss ( string_line.substr( 23, 4 ) );
ss >> new_sequence->length;
new_sequence->header = (char *) malloc( sizeof(char) * ( string_line.length() + 1 ) );
string_line.copy( new_sequence->header, string_line.length(), 0 );
(new_sequence->header)[string_line.length()] = '\0';
fgets( line, 2048, input_file );
string_line = line;
new_sequence->sequence = (char *) malloc( sizeof(char) * ( string_line.length() + 1 ) );
string_line.copy( new_sequence->sequence, string_line.length(), 0 );
(new_sequence->sequence)[string_line.length()] = '\0';
if( first_sequence == 0 )
{
sequences = new_sequence;
sequences->previous_sequence_structure = NULL;
first_sequence = 1;
}
else
{
sequences->next_sequence_structure = new_sequence;
new_sequence->previous_sequence_structure = sequences;
sequences = new_sequence;
}
}
else
{
cout << "Error: input file reading error." << endl;
}
}
fclose( input_file );
free( line );
sequence_structure *outer_sequence_node = sequences;
while( outer_sequence_node != NULL )
{
sequence_structure *inner_sequence_node = sequences;
string outer_sequence ( outer_sequence_node->sequence );
while( inner_sequence_node != NULL )
{
string inner_sequence ( inner_sequence_node->sequence );
if( outer_sequence_node->length > inner_sequence_node->length )
{
if( outer_sequence.find( inner_sequence ) != std::string::npos )
{
cout << "Deleting the sequence with id: " << inner_sequence_node->id << endl;
cout << inner_sequence_node->sequence << endl;
cout << "Found within the sequence with id: " << outer_sequence_node->id << endl;
cout << outer_sequence_node->sequence << endl;
sequence_structure *previous_sequence = inner_sequence_node->previous_sequence_structure;
sequence_structure *next_sequence = inner_sequence_node->next_sequence_structure;
free( inner_sequence_node->id );
free( inner_sequence_node->sequence );
free( inner_sequence_node->header );
if( next_sequence != NULL )
next_sequence->previous_sequence_structure = previous_sequence;
if( previous_sequence != NULL )
{
inner_sequence_node = previous_sequence;
free( previous_sequence->next_sequence_structure );
previous_sequence->next_sequence_structure = next_sequence;
}
}
}
inner_sequence_node = inner_sequence_node->previous_sequence_structure;
}
outer_sequence_node = outer_sequence_node->previous_sequence_structure;
}
output_file.open( argv[2], ios::out );
while( sequences->previous_sequence_structure != NULL )
{
sequences = sequences->previous_sequence_structure;
}
sequence_structure *current_sequence = sequences;
while( current_sequence->next_sequence_structure != NULL )
{
output_file << current_sequence->header;
output_file << current_sequence->sequence;
current_sequence = current_sequence->next_sequence_structure;
}
output_file << current_sequence->header;
output_file << current_sequence->sequence;
output_file.close();
while( sequences != NULL )
{
cout << "Freeing sequence with this id: " << sequences->id << endl;
free( sequences->id );
free( sequences->header );
free( sequences->sequence );
if( sequences->next_sequence_structure != NULL )
{
sequences = sequences->next_sequence_structure;
free( sequences->previous_sequence_structure );
}
else
{
sequences = NULL;
}
}
return 0;
}

_ttoi win c++ assertion failure

i have this code:
BOOLEAN Recurse = FALSE;
DWORD NumPasses = 1;
int _tmain( int argc, TCHAR *argv[] )
{
BOOL foundFileArg = FALSE;
int i;
if( argc < 2 ) {
return Usage( argv[0] );
}
for( i = 1; i < argc; i++ ) {
if( !_tcsicmp( argv[i], TEXT("/s") ) ||
!_tcsicmp( argv[i], TEXT("-s") )) {
Recurse = TRUE;
} else if( !_tcsicmp( argv[i], TEXT("/p") ) ||
!_tcsicmp( argv[i], TEXT("-p") )) {
// assertion failure
NumPasses = argc > i ? _ttoi( argv[i+1] ) : 1;
if( !NumPasses ) return Usage( argv[0] );
i++;
} else {
if( foundFileArg ) return Usage( argv[0] );
foundFileArg = TRUE;
}
}
return 0;
}
i get assertion failure,
Please suggest where the problem might be and where to look. Is it some problem with _ttoi function i'm using when it fails,
if i have to allocate a buffer,
how can i resolve it
thanks
this line
NumPasses = argc > i ? _ttoi( argv[i+1] ) : 1;
should be
NumPasses = argc > 1+i ? _ttoi( argv[i+1] ) : 1;
Nick is right; don't forget that arrays start at zero in C/C++. If there are 5 elements, it means argv[0] to argv[4] are valid - not argv[5].