I'm working on a college assignment and have been tasked with showing a basic mutex lock example. I've never worked with threads in any form, so I'm a total beginner working with POSIX threads in C++.
What I'm trying to get the program to do is create 1000 threads that increment a global integer by 1000.
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <thread>
pthread_t threadArr[1000];
pthread_mutex_t lock;
// Global int to increment
int numberToInc = 0;
void* incByTwo(void*)
{
pthread_mutex_lock(&lock);
for(int j = 0; j < 1000; j++){
numberToInc += 1;
}
pthread_mutex_unlock(&lock);
return NULL;
}
int main()
{
//Creates 1000 threads with incByTwo func
for(int i = 0; i < 1000; i++){
pthread_create(&threadArr[i], NULL, incByTwo, NULL);
}
std::cout << "\n" << numberToInc << "\n";
return 0;
}
The following produces a series of different results, obviously because the threads are executing concurrently, right?
Now, I've gotten it to work correctly by inserting
for(int i = 0; i < 1000; i++){
pthread_join(threadArr[i], NULL);
}
After the thread creation loop, but then removing the mutex locks, it still works. I've been trying to piece out how pthread_join works but I'm a little lost. Any advice?
Sorted a way to show the mutex lock in action. So when I output the global var in the function, without mutex locks it has the potential to show the results out of order.
Running the number range with mutex locks, out looks like:
1000
2000
3000
... (etc)
10000
With mutex locks removed, the output can vary in the order.
E.g.
1000
2000
4000
6000
3000
5000
7000
8000
9000
10000
While the final result of the three threads is correct, the sequence is out of order. In the context of this program it doesn't really matter but I'd imagine if it's passing inconsistently sequenced values it messes things up?
pthread_t threadArr[10];
pthread_mutex_t lock;
int numberToInc = 0;
void* incByTwo(void*)
{
pthread_mutex_lock(&lock);
for(int j = 0; j < 1000; j++){
numberToInc += 1;
}
std::cout << numberToInc << "\n";
pthread_mutex_unlock(&lock);
return NULL;
}
int main()
{
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
return 1;
}
for(int i = 0; i < 10; i++){
pthread_create(&threadArr[i], NULL, incByTwo, NULL);
}
pthread_join(threadArr[0], NULL);
return 0;
}
Related
I have a program where many threads do some computations and write a boolean true value in a shared array to tag the corresponding item as "dirty". This is a data race, reported by ThreadSanitizer. Nevertheless, the flag is never read from these threads, and since the same value is written by all threads, I wonder if it is an actually problematic data race.
Here is a minimal working example:
#include <array>
#include <cstdio>
#include <thread>
#include <vector>
int
main()
{
constexpr int N = 64;
std::array<bool, N> dirty{};
std::vector<std::thread> threads;
threads.reserve(3 * N);
for (int j = 0; j != 3; ++j)
for (int i = 0; i != N; ++i)
threads.emplace_back([&dirty, i]() -> void {
if (i % 2 == 0)
dirty[i] = true; // data race here.
});
for (std::thread& t : threads)
if (t.joinable())
t.join();
for (int i = 0; i != N; ++i)
if (dirty[i])
printf("%d\n", i);
return 0;
}
Compiled with g++ -fsanitize=thread, a data race is reported on the marked line. Under which conditions can this be an actual problem, i.e. the dirty flag for an item i would not be the expected value?
I'm trying to use 10 threads and each one needs to print his number and the printing needs to be synchronized. I'm doing it as homework and I have to use atomic variables to do it (no locks).
Here what I tried so far:
#include <atomic>
#include <thread>
#include <iostream>
#include <vector>
using namespace std;
atomic<bool> turn = true;
void print(int i);
int main()
{
vector<thread> threads;
for (int i = 1; i <= 10; i++)
{
threads.push_back(thread(print, i));
}
for (int i = 0; i < 10; i++)
{
threads[i].join();
}
return 0;
}
void print(int i)
{
bool f = true;
for (int j = 0; j < 100; j++)
{
while((turn.compare_exchange_weak(f, false)) == false)
{ }
cout << i << endl;
turn = turn.exchange(true);
}
}
output example:
24
9143
541
2
8
expected output:
2
4
9
1
4
3
1
5
4
10
8
You have 2 bugs in your use of atomic.
When compare_exchange_weak fails it stores the current value in the first parameter. If you want to keep trying the same value you need to set it back to the original value:
while ((turn.compare_exchange_weak(f, false)) == false)
{
f = true;
}
The second issue is that exchange returns the currently stored value so:
turn = turn.exchange(true);
Sets the value of turn back to false, you need just:
turn.exchange(true);
Or even just:
turn = true;
Synchronisation isn't actually necessary in this case as std::cout will do the synchronisation for you, single output operations wont overlap so you can just change your print function to the following and it will just work:
void print(int i)
{
for (int j = 0; j < 100; j++)
{
cout << std::to_string(i) + "\n";
}
}
Atomics aren't the right approach to this problem, your code is incredibly slow. Mutexes would probably be quicker.
My programming is going in dead lock.I am trying to print three numbers 3 4 5 sequentially for 50 times using three threads using semaphore synchronization.
Please help me.
Below is the code
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
using namespace std;
sem_t sem1;
sem_t sem2;
sem_t sem3;
void * fun1(void *)
{
for(int i = 0; i < 50 ; i++)
{
sem_wait(&sem1);
sem_wait(&sem3);
cout<<"3"
sem_post(&sem2);
sem_post(&sem3);
}
}
void * fun2(void *)
{
for(int i = 0; i < 50 ; i++)
{
sem_wait(&sem2);
sem_wait(&sem3);
cout<<"4";
sem_post(&sem3);
sem_post(&sem1);
}
}
void * fun3 (void *)
{
for(int i = 0; i< 50; i++)
{
sem_wait(&sem2);
sem_wait(&sem3);
cout<<"5";
sem_post(&sem1);
sem_post(&sem2);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_t t3;
sem_init(&sem1,0,1);
sem_init(&sem2,0,0);
sem_init(&sem3,0,1);
pthread_create(&t1,NULL,&fun1,NULL);
pthread_create(&t2,NULL,&fun2,NULL);
pthread_create(&t3,NULL,&fun3,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
return 1;
}
Please help me to understand and solve this deadlock.Provide suggestions also i can do this for example 3 4 5 6 using 4 etc threads
Please help me to understand and solve this deadlock.
There is indeed a deadlock in your code. Consider at the beginning, thread 1 first gets 2 semaphores and call cout << "3". After posting sem2 and sem3, it is possible that thread 3 immediately gets these 2 sem, then call cout << "5". However, after thread 3 posting sem1 and sem2, no one can reach a cout << statement, because sem3's value is 0 and everyone needs to pass a wait of sem3.
If you are wondering why there is totally no output, it's because the buffer inside iostream. For console output, "\n" will flush buffer, so if you replace "3" by "3\n", you can see the output.
Provide suggestions also i can do this for example 3 4 5 6 using 4 etc threads
In the following code, you should see the symmetry, which can be easily generalized to any number of thread. And you should always call sem_destroy after using semaphore, otherwise you might get system level resource leak.
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
using namespace std;
sem_t sem1;
sem_t sem2;
sem_t sem3;
void * fun1(void *)
{
for(int i = 0; i < 50 ; i++)
{
sem_wait(&sem1);
cout<<"3\n";
sem_post(&sem2);
}
}
void * fun2(void *)
{
for(int i = 0; i < 50 ; i++)
{
sem_wait(&sem2);
cout<<"4\n";
sem_post(&sem3);
}
}
void * fun3 (void *)
{
for(int i = 0; i< 50; i++)
{
sem_wait(&sem3);
cout<<"5\n";
sem_post(&sem1);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_t t3;
sem_init(&sem1,0,1);
sem_init(&sem2,0,0);
sem_init(&sem3,0,0);
pthread_create(&t1,NULL,&fun1,NULL);
pthread_create(&t2,NULL,&fun2,NULL);
pthread_create(&t3,NULL,&fun3,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
sem_destroy(&sem3);
return 1;
}
I've got simple c++ code that firstly creates 4 threads and then sends 1000 times number 1 to the c++ queue followed by four 0. Each of these threads tries to read from that queue and when any thread reads 0, it terminates and prints its local sum. If it reads 1 then it simply adds 1 to the sum. The reading is protected with mutex. Code works as intended in 4 out of 5 times, but sometimes I get double free or corruption (!prev) error... ...Abort core dumped. I've also debugged the code with gdb but only got received signal SIGABRT, Aborted ... ...at raise.c: No such file or directory". I'm not explicitly allocating or deallocating any memory. What could be causing the problem?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
std::queue<int> my_queue;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *process(void *arg){
int sum = 0;
while(1){
if(!my_queue.empty()){
pthread_mutex_lock(&mutex);
if (my_queue.front() == 1){
sum += 1;
my_queue.pop();
pthread_mutex_unlock(&mutex);
}
else{
my_queue.pop();
printf("Sum: %d\n", sum);
pthread_mutex_unlock(&mutex);
break;
}
}
}
return arg;
}
int main(void){
pthread_t id[4];
for(int i = 0; i < 4; i++){
if (pthread_create(&id[i], NULL, process, NULL) != 0){
fprintf(stderr, "%s\n", "Error creating thread!");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < 1000; i++){
my_queue.push(1);
}
for (int i = 0; i < 4; i++){
my_queue.push(0);
}
for (int i = 0; i < 4; i++){
pthread_join(id[i], NULL);
}
return EXIT_SUCCESS;
}
You have two problems:
Firstly you are pushing onto the queue without holding the lock, secondly you are testing if the queue is empty without holding the lock.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
std::queue<int> my_queue;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *process(void *arg){
int sum = 0;
bool keep_going = true;
while(keep_going){
pthread_mutex_lock(&mutex);
if(!my_queue.empty()){
if (my_queue.front() == 1){
sum += 1;
}
else{
keep_going=false;
}
}
my_queue.pop();
pthread_mutex_unlock(&mutex);
}
printf("Sum: %d\n", sum); // Don't do IO while holding a lock!
return arg;
}
int main(void){
pthread_t id[4];
// Initialize queue *before* creating threads.
for (int i = 0; i < 1000; i++){
my_queue.push(1);
}
for (int i = 0; i < 4; i++){
my_queue.push(0);
}
// Create threads
for(int i = 0; i < 4; i++){
if (pthread_create(&id[i], NULL, process, NULL) != 0){
fprintf(stderr, "%s\n", "Error creating thread!");
exit(EXIT_FAILURE);
}
}
// Join them.
for (int i = 0; i < 4; i++){
pthread_join(id[i], NULL);
}
return EXIT_SUCCESS;
}
If you want to add to the queue after creating the threads, you need something like:
pthread_mutex_lock(&mutex);
my_queue.push(value);
pthread_mutex_unlock(&mutex);
Inside the for-loops. Also, there is then a real chance of the queue emptying before you get to the zeros. Either do it properly by waiting on semaphores, or the queue loop needs to becomes something like:
pthread_mutex_lock(&mutex);
if(my_queue.empty()){
pthread_mutex_unlock(&mutex);
usleep(1);
pthread_mutex_lock(&mutex);
} else {
Where the thread will briefly sleep to let the queue fill up.
Also, you are writing in C++. Learn to write a RAII class to call pthread_mutex_lock and unlock.
I wrote an simple code that should make 1000 of threads, do some job, join them, and replay everything 1000 times.
I have a memory leak with this piece of code and I don't understand why. I've been looking for solution pretty much everywhere and can't find one.
#include <iostream>
#include <thread>
#include <string>
#include <windows.h>
#define NUM_THREADS 1000
std::thread t[NUM_THREADS];
using namespace std;
//This function will be called from a threads
void checkString(string str)
{
//some stuff to do
}
void START_THREADS(string text)
{
//Launch a group of threads
for (int i = 0; i < NUM_THREADS; i++)
{
t[i] = std::thread(checkString, text);
}
//Join the threads with the main thread
for (int i = 0; i < NUM_THREADS; i++) {
if (t[i].joinable())
{
t[i].join();
}
}
system("cls");
}
int main()
{
for(int i = 0; i < 1000; i++)
{
system("cls");
cout << i << "/1000" << endl;
START_THREADS("anything");
}
cout << "Launched from the main\n";
return 0;
}
I'm not sure about memory leaks, but you certainly have a memory error. You shouldn't be doing this:
delete &t[i];
t[i] was not allocated with new and it can't be deleted. You can safely remove that line.
As for memory consumption, you need to ask yourself whether you really need to spawn 1 million threads. Spawning threads isn't cheap, and it is unlikely that your platform will be able to run more than a handful of them concurrently.