Parallel merge sort useing _beginthreadex windows API in C++ - c++

I'm trying to implement merge sort using win32 _beginthreadex multiple threads in c++. basically it uses _beginthreadex instead of function call to make recursion in each thread. so it will has as many threads as possible. the while loop after the two _beginthreadex call is to check if the children threads finish there job. But when the program access the array a and b, it gives an error that unable to read the memory, I can't find what the problem is. It seems that in the sorting section in children threads the program try to access invalid memory address that info->b goes to the address 0xcccccccc {???}
Thank you
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <sstream>
#include <array>
#include <stdio.h>
using namespace std;
struct ThreadInfo
{
int* a;
int* b;
int low;
int high;
bool run;
};
unsigned __stdcall mergesort(void* x) {
ThreadInfo* info = (ThreadInfo*)x;
if ((info->low) < (info->high))
{
int pivot = ((info->low)+(info->high))/2;
ThreadInfo lowInfo;
ThreadInfo highInfo;
lowInfo.a=info->a;
lowInfo.low=info->low;
lowInfo.high=pivot;
lowInfo.run=true;
highInfo.b=info->b;
highInfo.low=pivot+1;
highInfo.high=info->high;
highInfo.run=true;
//HANDLE myhandlerUp, myhandlerDown;
//creat sub-thread
_beginthreadex(NULL, 0, mergesort, &lowInfo, 0, 0);
//WaitForSingleObject(myhandlerUp,INFINITE);
_beginthreadex(NULL, 0, mergesort, &highInfo, 0, 0);
//WaitForSingleObject(myhandlerDown,INFINITE);
//check if any child threads are working
bool anyRun = true;
while (anyRun)
{
anyRun = false;
anyRun = lowInfo.run || highInfo.run;
}
//doing merge sort
int h,i,j,k,low, high;
low = info->low;
high = info->high;
h=low;
i=low;
j=pivot+1;
while((h<=pivot)&&(j<=high))
{
if(info->a[h]<=info->a[j])
{
info->b[i]=info->a[h];
h++;
}
else
{
info->b[i]=info->a[j];
j++;
}
i++;
}
if(h>pivot)
{
for(k=j; k<=high; k++)
{
info->b[i]=info->a[k];
i++;
}
}
else
{
for(k=h; k<=pivot; k++)
{
info->b[i]=info->a[k];
i++;
}
}
for(k=low; k<=high; k++) info->a[k]=info->b[k];
}
info->run = false;
return 0;
}
void main()
{
ThreadInfo info;
int inputArr[12] = {12,10,43,23,-78,45,123,56,98,41,90,24};
int copiedArr[12]={0,0,0,0,0,0,0,0,0,0,0,0};
info.a=inputArr;
info.b=copiedArr;
for(int i=0; i<12; i++)
cout<<info.a[i]<<" ";
cout<<endl;
info.low=0;
info.high=(11);
info.run=true;
_beginthreadex(NULL, 0, mergesort, &info, 0, 0);
bool finish = info.run;
while(finish){
cout<<"Running...."<<endl;
Sleep(1000);
}
cout<<"After run the result is "<<endl;
for(int i=0; i<12; i++)
cout<<inputArr[i]<<" ";
cout<<endl;
getchar();
}

Related

Storing and writing vector to queue c++

#include <iostream>
#include <queue>
#include <thread>
#include <process.h>
#include <windows.h>
#include <stdlib.h>
int g_Width = 100;
std::queue<std::vector<unsigned short>> BufferQueue;
bool dataRead = false;
unsigned short* g_pImgBuf = NULL;
unsigned int _stdcall Write(void* arg) {
std::vector<unsigned short> data;
data.reserve(g_Width);
int line = 0;
while (dataRead)
{
if (!dataRead)
break;
for (int i = 0; i < g_Width; i++) {
data.push_back(i);
}
BufferQueue.push(data);
data.clear();
}
_endthreadex(0);
return 0;
}
unsigned int _stdcall Read(void* arg) {
std::vector<unsigned short> data;
data.reserve(g_Width);
unsigned short color = 0;
int line = 0;
while (dataRead)
{
g_pImgBuf = new unsigned short[g_Width];
if (!BufferQueue.empty()) {
data = BufferQueue.front();
BufferQueue.pop();
}
else if (!dataRead)
break;
else {
continue;
}
for (int j = 0; j < g_Width; j++) {
color = data[j];
color += 2;
g_pImgBuf[j] = color;
}
data.clear();
}
if (g_pImgBuf) { free(g_pImgBuf); g_pImgBuf = NULL; }
_endthreadex(0);
return 0;
}
int main()
{
dataRead = true;
HANDLE r_hThread = NULL;
unsigned r_threadID;
r_hThread = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, &r_threadID);
HANDLE w_hThread = NULL;
unsigned w_threadID;
w_hThread = (HANDLE)_beginthreadex(NULL, 0, Write, NULL, 0, &w_threadID);
while (true)
{
Sleep(100);
}
}
The following error occurred
vector subscript out of range 1501 error
In the middle of the thread function
Give it sleep (2) and it works sometimes but soon I get an error.
If the vector is the problem, is there any other way to store the array in the queue?
I don't know where the problem is
Is there a good way?
You simply cannot do this in such a simplistic way. If you want one thread to pick messages off the queue that are being written by another thread you need mtuexes and condition variables. This is not a trivial task. I suggest a lot of googling. I will look too and updat here if I find a good link
https://juanchopanzacpp.wordpress.com/2013/02/26/concurrent-queue-c11/
https://gist.github.com/ictlyh/f8473ad0cb1008c6b32c41f3dea98ef5

How to avoid global semaphores and queues when using threads

I have a problem with my code. It works, but I cannot avoid using global semaphores. I have 3 thread functions. the first is run by 10 threads. The second and third are run by 2 threads each. These threads should run without having race conditions. In addition, they should communicate with each other. I use a user defined queue class for communications between threads and between the threads and main. Also, I use the semaphores to achieve mutual exclusion between the threads. Since I declare the instance of the queue class and the semaphores in a global manner, I do not have to pass them to any function. They are accessible to any function in this program. However, this is not a healthy way to write programs. Therefore, I ask you, how to declare the queue and the semaphores locally, and what is the best way to pass them between threads.
// queueString header
#include <string>
#include <queue>
#include <semaphore.h>
using namespace std;
class queueString
{
public:
queueString();
~queueString();
void qPush(string str);
string qPop();
private:
sem_t queueSem;
queue <string> q;
};
//queueString class
#include "queueString.h"
using namespace std;
// queue class that will enqueue and dequeue atomically.
queueString::queueString(){
sem_init(&queueSem, 0, 1);
}
queueString::~queueString(){}
void queueString::qPush(string str){
sem_wait(&queueSem);
this->q.push(str);
sem_post(&queueSem);
}
string queueString::qPop(){
sem_wait(&queueSem);
string str = this->q.front();
q.pop();
sem_post(&queueSem);
return str;
}
//The three threads with main
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include "queueString.h"
using namespace std;
//My question is here, How to declare the variables below locally, and where
// is the right place to declare them, and how to pass them to threads?
sem_t s12, s13, s21, s31, sthr1, sthr2[2], sthr3[2], printSem;
sem_t idInitializationSemMainToThread, idInitializationSemThreadToMain;
queueString q = queueString();
#define THR1NUM 10
#define THR2NUM 2
#define THR3NUM 2
void printString(string str);
void *thread1(void* arg){
sem_wait(&idInitializationSemMainToThread);
int *pnum = (int *)arg;
int thr_1_ID = *pnum;
sem_post(&idInitializationSemThreadToMain);
sem_wait(&sthr1);
string value= "THR1 ";
value.append(to_string(thr_1_ID));
q.qPush(value);
sem_post(&s12);
sem_wait(&s21);
value= "2nd Iteration THR1 ";
value.append(to_string(thr_1_ID));
q.qPush(value);
sem_post(&s13);
sem_wait(&s31);
sem_post(&sthr1);
}
void *thread2(void* arg){
sem_wait(&idInitializationSemMainToThread);
int *pnum = (int *)arg;
int thr_2_ID = *pnum;
sem_post(&idInitializationSemThreadToMain);
while (true)
{
sem_wait(&sthr2[thr_2_ID]);
sem_wait(&s12);
string readVal = q.qPop();
printString(readVal + ", THR2 "+ to_string(thr_2_ID));
if (thr_2_ID==0)
sem_post(&sthr2[1]);
else
sem_post(&sthr2[0]);
sem_post(&s21);
}
}
void *thread3(void* arg){
sem_wait(&idInitializationSemMainToThread);
int *pnum = (int *)arg;
int thr_3_ID = *pnum;
sem_post(&idInitializationSemThreadToMain);
while (true)
{
sem_wait(&sthr3[thr_3_ID]);
sem_wait(&s13);
string readVal = q.qPop();
printString(readVal + " THR3 " + to_string(thr_3_ID));
if (thr_3_ID == 0)
sem_post(&sthr3[1]);
else
sem_post(&sthr3[0]);
sem_post(&s31);
}
}
int main(){
pthread_t thr1[THR1NUM], thr2[THR2NUM], thr3[THR3NUM];
sem_init(&s12, 0, 0);
sem_init(&s13, 0, 0);
sem_init(&s31, 0, 0);
sem_init(&s21, 0, 0);
sem_init(&printSem, 0, 1);
sem_init(&sthr1, 0, 0);
for (int i = 0; i < 2;i++)
sem_init(&sthr2[i], 0, 0);
for (int i = 0; i < 2;i++)
sem_init(&sthr3[i], 0, 0);
sem_init(&idInitializationSemMainToThread, 0, 0);
sem_init(&idInitializationSemThreadToMain, 0, 0);
int *pnum =(int *) malloc(sizeof(int));
for (int j = 0; j < THR2NUM;j++){
*pnum = j;
pthread_create(&thr2[j], NULL, thread2, (void *)pnum);
sem_post(&idInitializationSemMainToThread);
printString("thr2 "+to_string(j)+ " created");
sem_wait(&idInitializationSemThreadToMain);
}
for (int k = 0; k < THR3NUM;k++){
*pnum = k;
pthread_create(&thr3[k], NULL, thread3,(void *) pnum);
sem_post(&idInitializationSemMainToThread);
printString("thr3 "+to_string(k)+ " created");
sem_wait(&idInitializationSemThreadToMain);
}
for (int i = 0; i < THR1NUM;i++){
*pnum = i;
pthread_create(&thr1[i], NULL, thread1,(void *) pnum);
sem_post(&idInitializationSemMainToThread);
printString("thr1 "+to_string(i)+ " created");
sem_wait(&idInitializationSemThreadToMain);
}
sem_post(&sthr2[0]);
sem_post(&sthr3[0]);
sem_post(&sthr1);
for (int i = 0; i < THR1NUM;i++){
pthread_join(thr1[i], NULL);
printString("thr1 "+to_string(i)+ " joined");
}
for (int i = 0; i < THR2NUM; i++){
pthread_cancel(thr2[i]);
printString("thr2 "+to_string(i)+ " exited");
}
for (int i = 0; i < THR3NUM;i++){
pthread_cancel(thr3[i]);
printString("thr3 "+to_string(i)+ " exited");
sem_post(&printSem);
}
sem_destroy(&s12);
sem_destroy(&s21);
sem_destroy(&s13);
sem_destroy(&s31);
sem_destroy(&sthr1);
free(pnum);
}
// function to print strings atomically.
void printString(string str){
sem_wait(&printSem);
printf("%s\n", str.c_str());
sem_post(&printSem);
}

c++ trying to add Peterson algorithm to avoid race condition in shared memory

I have written two program (program 1 and program 2) to communicate with each other using shared memory. program 1 reads from a file a sentence and pass it after modification to get first letter of each word and its size to the next program ( program 2) . I faced race condition problem. I added Peterson algorithm but once I execute the 2 programs one in foreground and one in background I didn't get any result.
-once i remove the Peterson algorithm my programs work
-i'm working in linux using c++
program 1
#include<iostream>
#include<fstream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int filesize(){
ifstream input;
input.open("file1.txt");
string temp;
int i = 0;
while(input>>temp){i++;}
input.close();
return i;
}
struct shdata
{
char c;
int n;
int size;
bool flag[2];
int turn;
};
int main(){
ifstream input;
input.open("file1.txt");
int shmid;
key_t key = 8006;
struct shdata *shm;
shmid = shmget(key, sizeof(struct shdata), IPC_CREAT | 0666);
if(shmid < 0){
cout<<"Error .. Can not get memory\n";
exit(0);
}
shm = (struct shdata *)shmat (shmid, NULL, 0);
if(shm <= (struct shdata *)(0))
{
cout<<"Errors.. Can not attach\n";
exit(1);
}
shm->flag[0]=false;
shm->flag[1]=true;
string temp;
while(input>>temp){
shm->flag[0]=true;
shm->turn = 1;
while(shm->flag[1]== true && shm-> turn == 1 );
shm->c=temp[0];
shm->n=temp.size();
shm->size = filesize();
shm->flag[0]=false;
sleep(1);
}
return 0;
}
program 2
#include<iostream>
#include<fstream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int filesize(){
ifstream input;
input.open("file1.txt");
string temp;
int i = 0;
while(input>>temp){i++;}
input.close();
return i;
}
struct shdata
{
char c;
int n;
int size;
bool flag[2];
int turn;
};
int main(){
int shmid;
key_t key = 8006;
struct shdata *shm;
shmid = shmget(key, sizeof(struct shdata), 0);
if(shmid < 0)
{
cout<<"Error .. Can not get memory\n";
exit(0);
}
shm = (struct shdata *)shmat (shmid,0, 0);
if(shm <= (struct shdata *)(0))
{
cout<<"Error .. Can not attach\n";
exit(1);
}
int c =0;
while(c<shm->size){
shm->flag[1] = true;
shm->turn=0;
while( shm->flag[0]==false && shm->turn == 0);
sleep(1);
for(int i = 0; i < shm->n ;i++)
{
cout<<shm->c;
}
cout<<endl;
shm->flag[1]=false;
c++;
}
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
program 2 never gets into the while(c<shm->size) loop because at that point shm->size is 0. To get around it, progran 1 should initialize shm->size before program 2 reaches that point. This might lead to another race condition because there doesn't seem to be any mechanism to ensure that the shared memory is initialized by program 1 before program 2 starts using it.
It seems to work without the Peterson algorithm because in that case program 1 doesn't wait on the flag and initializes shm->size further down in the loop.
You are using the flag member to synchronize you 2 programs but this cant work because you cant suppose the sequence of read/writes. You must use a small dialect in order to make your two programs starts in the correct order.

Producer-Consumer Issue

Hi I'm trying to write an algorithm for solving the producer-consumer problem and I've hit a roadblock. This is the output I am getting from my code:
Producing: 6
6 0 0 0 0 0 0 0 0 0 END
and then the program exits. I'm not sure where I went wrong? Did I do something wrong in creating a circular buffer?
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <fstream>
using namespace std;
#define BUFFER_SIZE 10
void *produce(void *);
void *consume(void *);
int produceItem(void);
void insertItem(int item);
void removeItem(void);
void printBuffer(void);
int head = 0;
int tail = 0;
int item;
int bufferCount = 0;
pthread_t producer, consumer;
pthread_cond_t Buffer_Not_Full=PTHREAD_COND_INITIALIZER;
pthread_cond_t Buffer_Not_Empty=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock;
sem_t sem_filledSlots;
sem_t sem_emptySlots;
int buffer[BUFFER_SIZE];
int main() {
int emptyCount;
int item;
srand (time(NULL));
sem_init(&sem_filledSlots, 0, 0);
sem_init(&sem_emptySlots, 0, BUFFER_SIZE);
sem_getvalue(&sem_emptySlots, &emptyCount);
pthread_create (&producer, NULL, &produce, NULL);
pthread_create (&consumer, NULL, &consume, NULL);
return 0;
}
void *produce(void *)
{
for(int i = 0; i <15; i++)
{
item = produceItem();
sem_wait(&sem_emptySlots);
pthread_mutex_lock(&lock);
printf("Producing: %d \n", item);
buffer[head] = item;
head = (head + 1) % BUFFER_SIZE;
printBuffer();
pthread_mutex_unlock(&lock);
sem_post(&sem_filledSlots);
}
}
void *consume(void *)
{
for(int i = 0; i <15; i++)
{
sem_wait(&sem_filledSlots);
pthread_mutex_lock(&lock);
printf("Consuming %d \n", buffer[tail]);
buffer[tail] = 0;
tail = (tail + 1) % BUFFER_SIZE;
bufferCount--;
printBuffer();
pthread_mutex_unlock(&lock);
sem_post(&sem_emptySlots);
}
}
int produceItem(void)
{
int x = (rand()%11 + 1);
return x;
}
void printBuffer(void)
{
for(int i = 0; i <BUFFER_SIZE; i++)
{
printf("%d ", buffer[i]);
}
printf("END \n");
}
you're missing pthread_join before exiting the program:
....
pthread_join(producer,NULL);
pthread_join(consumer,NULL);
return 0;
....

stl map simultaneous write sample code

I want to simulate the abnormal behavior of stl map in simultaneous write condition.
Here I am using a single map and simultaneously inserting data from multiple threads.
As we are using only one map object, hence it should not allow.
Please go through the following sample code
#include <iostream>
#include <map>
#include <iterator>
#include <algorithm>
extern "C"
{
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
}
using namespace std;
//functor to print map
struct PrintMp
{
void operator()(pair<int,int> pr)
{
cout<<pr.first<<" => "<<pr.second<<endl;
}
};
//thread 1
//inserts continuous no from 0 to 4999
void* ins_th1(void *arg)
{
map<int, int> *mp = static_cast<map<int, int>* >(arg);
for(int i =0 ; i<5000; i++)
mp->insert(pair<int,int>(i, i+1000));
return NULL;
}
//thread 1
//inserts continuous no from 0 to 4999
void* ins_th2(void *arg)
{
map<int, int> *mp = static_cast<map<int,int>* >(arg);
for(int i=5000; i<10000; i++)
mp->insert(pair<int, int>(i, i+2000));
return NULL;
}
int main()
{
typedef map<int, int> IntMapType;
IntMapType mp;
PrintMp MpPrintObj;
int rc;
pthread_t th1, th2;
//thread 1 creation
rc = pthread_create(&th1, NULL, ins_th1, static_cast<void*>(&mp));
if ( rc != 0)
{
cerr<<strerror(rc)<<"in thread1"<<endl;
exit(EXIT_FAILURE);
}
//thread 2 creation
rc = pthread_create(&th2, NULL, ins_th2, static_cast<void*>(&mp));
if(rc!=0)
{
cerr<<strerror(rc)<<"in thread2"<<endl;
exit(EXIT_FAILURE);
}
//lets wait for the thread to finish
rc = pthread_join(th1, NULL);
if ( rc != 0)
{
cerr<<strerror(rc)<<"join failure for thread1"<<endl;
exit(EXIT_FAILURE);
}
rc = pthread_join(th2, NULL);
if ( rc != 0)
{
cerr<<strerror(rc)<<"join failure for thread2"<<endl;
exit(EXIT_FAILURE);
}
cout<<"Map data"<<endl;
//now print it
for_each(mp.begin(), mp.end(), MpPrintObj);
cout<<endl;
return 0;
}
But it doesn't work. Can anyone suggest me some approach ?
You are only testing insertion, which may or may not be implemented in a thread safe fashion, for all you know. But, your test is not complete. Allow the threads to write the same key into the map, and you will likely experience an error that would not happen without multiple threads.
// ins_th1
for(int i =0 ; i<10000; i++)
mp->insert(pair<int,int>(i, i+1000));
// ins_th2
for(int i=0; i<10000; i++)
mp->insert(pair<int, int>(i, i+2000));
You should test deletion from the map as well. When I modified your program to populate the map, before launching the threads, and only had the threads remove things from the map, the program live-locked.
// ins_th1
for(int i =0 ; i<5000; i++)
mp->erase(i);
// ins_th2
for(int i=5000; i<10000; i++)
mp->erase(i);
// near top of main
for(int i =0 ; i<5000; i++)
mp.insert(pair<int,int>(i, i+1000));
for(int i=5000; i<10000; i++)
mp.insert(pair<int, int>(i, i+2000));
//... launch threads
I tried to implement as you said.
But despite not using any synchronization mechanism, I am getting the perfect result.