Thread hangs in pthread_rwlock_t - c++

I have this simple thread creation progrm in c++, during when a RW lock is declared globally, progrmm executes as expected, but when the same lock declaration is made local (i.e., Inside the function) only one thread executes, the other thread hangs.
WORKING:
#include <iostream>
#include <pthread.h>
using namespace std;
int i = 0;
**pthread_rwlock_t mylock;** //GLOBAL
void* IncrementCounter(void *dummy)
{
cout << "Thread ID " << pthread_self() << endl;
int cnt = 1;
while (cnt < 50)
{
pthread_rwlock_wrlock(&mylock);
++i;
pthread_rwlock_unlock(&mylock);
++cnt;
cout << "Thread ID ( " << pthread_self() << " ) Incremented Value : " << i << endl;
}
}
int main()
{
pthread_t thread1,thread2;
int ret, ret1;
ret = pthread_create(&thread1,NULL,IncrementCounter,NULL);
ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
}
*NON WORKING:*
#include <iostream>
#include <pthread.h>
using namespace std;
int i = 0;
void* IncrementCounter(void *dummy)
{
cout << "Thread ID " << pthread_self() << endl;
int cnt = 1;
**pthread_rwlock_t mylock;** //LOCAL
while (cnt < 50)
{
pthread_rwlock_wrlock(&mylock);
++i;
pthread_rwlock_unlock(&mylock);
++cnt;
cout << "Thread ID ( " << pthread_self() << " ) Incremented Value : " << i << endl;
}
}
int main()
{
pthread_t thread1,thread2;
int ret, ret1;
ret = pthread_create(&thread1,NULL,IncrementCounter,NULL);
ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
}
What could be the possible reason for this?

In neither case are you correctly initialising the mylock variable - you are just getting "lucky" in the first case. The correct initialisation in the global case would be:
pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER;
In the local case, if you want your threads to be accessing the same lock, then it has to be declared static:
static pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER;
That's what you want in this case, because you're protecting access to the global i. The lock should be associated with the data, so if i is global then really it makes sense for mylock to be global also.
If you really wanted non-static locks (which in this case, you don't), you would use:
pthread_rwlock_t mylock;
pthread_rwlock_init(&mylock, NULL);
followed by:
pthread_rwlock_destroy(&mylock);
at the end of the function.

In addition to what the other answers say, consider that in C and C++ all variables with static storage (e.g. mylock in your first example) are initialized to zero.
Simplifying, pthread_rwlock_t is a struct.
In your first example, mylock has static storage duration, so all of its internal members were initialized to zero. By chance, this equivalent to the "unlocked" state of pthread_rwlock_t, as the macro PTHREAD_RWLOCK_INITIALIZER mentioned in another answer initializes exactly everything to zero; in nptl/sysdeps/pthread/pthread.h you can find:
#define PTHREAD_RWLOCK_INITIALIZER \
{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
Therefore all runs of your first example will always exhibit the same behavior (i.e. the lock will start unlocked).
In your second example, mylock is not initialized, because it has automatic storage duration. The behavior will then be dependent on what other values happen to be lying the that uninitialized area of memory. Most of the times, the lock with start in "locked" state, but, if you're lucky (on unlucky) enough, it will instead start unlocked.

The reason is quite clear, you even say so yourself... In the working version the variable is global, while in the non-working the variable is local.
A local variable is only known inside the function, during that call. So if a function is called twice then the variable is unique on both these calls.
If you want to use a local variable, you can mark it static, as that makes it "static" between all invocations of the function.
I suggest you read more about variable scoping and lifetime.

Related

How to get value from declaration only once?

Say I have a function that I want to call multiple times. At the start of this function I have declared an integer for a value of zero, and at the end of it I increased its value by one. Now I want to save the new value so when I call the function again the value of that variable becomes 2. Is there a way to do that besides getting the variable from another function or declare it at the top of line codes out of the functions?
TLDR
Yes, using the static keyword.
It changes the lifetime of the object declared with it, that becomes available for the whole duration of the program.
That said, you should be careful with using static local variables, because you're adding a state to the function execution.
#include <iostream>
using namespace std;
void printX()
{
static int x;
cout << "x: " << x << endl;
++x;
}
int main()
{
for (int i = 0; i < 10; ++i)
printX();
}
https://www.jdoodle.com/iembed/v0/909
There's more to the static keyword and you should look into it.
I'd suggest you read at least a couple of articles about it:
https://en.wikipedia.org/wiki/Static_(keyword)#Common_C
https://www.geeksforgeeks.org/static-variables-in-c/
you can use a static variable declared inside the function, since it is static the initialization to zero will happen only once and the rest of the time you call the function it will retain its value...
here is an example:
#include <iostream>
void foo(int x)
{
static int counter{0};
std::cout<< "this is x: " << x << std::endl;
counter++;
std::cout<< "this is counter: " << counter << std::endl;
}
int main() {
foo(1);
foo(10);
std::cout<< "something else in the app is executed... " << std::endl;
foo(101);
return 0;
}
and here the output:
this is x: 1
this is counter: 1
this is x: 10
this is counter: 2
something else in the app is executed...
this is x: 101
this is counter: 3

Local variable initialized in a condition not recognized?

I am learning c++ and I came across a really odd phenomenon in a program. I haven't seen any documentation on this problem. Why is that when I initialize a variable inside of a conditional statement it isn't recognized outside of it? Is the variable local to the conditional statement?
Here is an example:
#include "stdafx.h"
#include <iostream>
using namespace std;
/*scope / range of variables */
int global;
int main()
{
int local = rand();
cout << "value of global " << global << endl;
cout << "value of local " << local << endl;
int test = 10;
if (test == 0)
{
int result = test * 10;
}
cout << "result :" << result << endl;
return 0;
}
In this case result is undefined. Can someone please explain what is going on?
As pointed out in the comments, your declaration of result is local inside the if() blocks scope you provided:
if (test == 0)
{ // Defines visibility of any declarations made inside
int result = test * 10;
} // ^^^^^^
Hence the statement
cout << "result :" << result << endl;
would lead to a compiler error, since result isn't visible for the compiler at this point outside that scope.
But even if you declare result correctly outside of the scope block, your logic
int result = 0; // Presumed for correctness
int test = 10;
if (test == 0)
{
result = test * 10; // Note the removed declaration
}
doesn't make much sense, since test was given the value 10 immediately before testing it against the value 0 in your your if() statements condition, and the condition never would become true.

Seg-fault when trying to swapcontext() into a struct member that is stored in a queue

I've defined a struct called thread with a member called ucontext* tctx.
In a function called create_thread(), I create a thread object on the heap and define each one of its members (including the members of the ucontext object). I then add the pointer to that thread object into a queue-container.
When I pop the queue to swap into a thread's context, I seg-fault. I'm not sure why this happens.
Here is the full code:
#include <iostream>
#include <queue>
#include <ucontext.h>
#define STACK_SIZE 262144
using namespace std;
typedef struct thread
{
int thread_id;
ucontext* tctx;
char* sp;
}thread;
int thread_id;
ucontext_t* ctx1; //Unused, currently
ucontext_t* cur;
queue<thread*> ready_queue;
/* Function Declaration */
thread* create_thread(int,int);
void foo1(int);
int main(int argc, char** argv)
{
cout << " PROGRAM START ***** \n";
/* Create 'i' number of threads */
for(int i = 0; i < 2; i++)
{
cout << "\nready_queue size before creating thread = " << ready_queue.size() << endl;
cout << "Calling create thread ... id=" << i << endl;
create_thread(i, i*1000);
cout << "ready_queue size after creating thread = " << ready_queue.size() << endl;
}
cout << " \t>> THREADS CREATED \n";
cout << " \t>> SWITCHING CONTEXT \n";
/* Save current context to cur, swap context to first thread in queue */
swapcontext(cur, ready_queue.front()->tctx); //Seg fault!
cout << " PROGRAM TERMI ***** \n";
return 0;
}
thread* create_thread(int id, int arg)
{
static int num_threads = 0;
/* Create a new thread struct, ucontxt for the thread, and put in ready queue */
thread* n = new thread;
getcontext(n->tctx);
n -> thread_id = id;
n -> tctx = new ucontext_t;
n -> sp = new char[STACK_SIZE];
n->tctx->uc_stack.ss_sp = n->sp;
n->tctx->uc_stack.ss_size = STACK_SIZE;
n->tctx->uc_stack.ss_flags = 0;
n->tctx->uc_link = NULL;
makecontext(n->tctx, (void(*)()) foo1, 1, arg); //Thread shall call foo() with argument 'arg'
/* Push new thread into ready_queue */
ready_queue.push(n);
num_threads++;
cout << "Thread #" << num_threads << " was created. Thread.ID[" << id << "]\n";
return n;
}
//Application function
void foo1(int arg)
{
cout << "Calling from foo1(). I have " << arg << "!\n";
}
Edited:
I noticed that if I call getcontext(n->tctx); after n -> tctx = new ucontext_t; the problem is resolved. It seems to be that the problem might be that getcontext was trying to initialize something in the heap that had not yet been allocated.
The ucontext_t* cur pointer is dangling, that is why it swapcontext crashes. You could allocate a valid value (new ucontext_t), but it's better to make its type ucontext_t rather than a pointer. The same also counts for thread.tctx and there is no need to keep thread.sp a pointer either.
However, C++11 has std::thread which is a much better alternative to what you are trying to do and this would be the proper C++ approach. Also if you want to learn something new, I'd recommend to focus on std::thread instead. There's a nice tutorial here: https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/
By the way, in your example getcontext(n->tctx); is also called on an uninitialized tctx and you have a lot of unfreed memory at the end of your program...

Is it safe/efficient to cancel a c++ thread by writing to an outside variable?

I have a search problem, which I want to parallelize. If one thread has found a solution, I want all other threads to stop. Otherwise, if all threads exit regularly, I know, that there is no solution.
The following code (that demonstrates my cancelling strategy) seems to work, but I'm not sure, if it is safe and the most efficient variant:
#include <iostream>
#include <thread>
#include <cstdint>
#include <chrono>
using namespace std;
struct action {
uint64_t* ii;
action(uint64_t *ii) : ii(ii) {};
void operator()() {
uint64_t k = 0;
for(; k < *ii; ++k) {
//do something useful
}
cout << "counted to " << k << " in 2 seconds" << endl;
}
void cancel() {
*ii = 0;
}
};
int main(int argc, char** argv) {
uint64_t ii = 1000000000;
action a{&ii};
thread t(a);
cout << "start sleeping" << endl;
this_thread::sleep_for(chrono::milliseconds(2000));
cout << "finished sleeping" << endl;
a.cancel();
cout << "cancelled" << endl;
t.join();
cout << "joined" << endl;
}
Can I be sure, that the value, to which ii points, always gets properly reloaded? Is there a more efficient variant, that doesn't require the dereferenciation at every step? I tried to make the upper bound of the loop a member variable, but since the constructor of thread copies the instance of action, I wouldn't have access to that member later.
Also: If my code is exception safe and does not do I/O (and I am sure, that my platform is Linux), is there a reason not to use pthread_cancel on the native thread?
No, there's no guarantee that this will do anything sensible. The code has one thread reading the value of ii and another thread writing to it, without any synchronization. The result is that the behavior of the program is undefined.
I'd just add a flag to the class:
std::atomic<bool> time_to_stop;
The constructor of action should set that to false, and the cancel member function should set it to true. Then change the loop to look at that value:
for(; !time_to_stop && k < *ii; ++k)
You might, instead, make ii atomic. That would work, but it wouldn't be as clear as having a named member to look at.
First off there is no reason to make ii a pointer. You can have it just as a plain uint64_t.
Secondly if you have multiple threads and at least one of them writes to a shared variable then you are going to have to have some sort of synchronization. In this case you could just use std::atomic<uint64_t> to get that synchronization. Otherwise you would have to use a mutex or some sort of memory fence.

Deadlock / Access violation in my code even though I've mutually excluded it

So I'm trying to better understand multi threading and how deadlocks happen and how to avoid them so I put together a small piece of code. Basically I have two threads which share an int pointer.
Each thread both reads and writes from/to the value being pointed to.
When a thread writes (increases the value by 1), I lock a global mutex around it.
When it reads (couts it to console), I lock a global mutex around it.
Here's my code first of all:
// DeadLockTest.cpp
//
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
void foo(int* p);
void bar(int* p);
mutex mut;
int _tmain(int argc, _TCHAR* argv[])
{
int x = 5;
int* p = &x;
thread first(bind(foo, p));
thread second(bind(bar, p));
first.join();
second.join();
cout << "threads done";
cin.ignore();
return 0;
}
void foo(int* p){
int i = 0;
while(1){
i++;
mut.lock();
*p++;
mut.unlock();
mut.lock();
cout << "foo: " << *p << endl;
mut.unlock();
}
}
void bar(int* p){
int i = 0;
while(1){
i++;
mut.lock();
*p--;
mut.unlock();
mut.lock();
cout << "bar" << *p << endl;
mut.unlock();
}
}
I eventually get an exception:
Unhandled exception at 0x008E608F in DeadLockTest.exe: 0xC0000005: Access violation reading location 0x003B0000.
First things first, why am I getting the exception? I've mutually locked the resource from being accessed from the other thread. If I've done something wrong, this leads to another question. The exception always happens on the cout statement in foo, it never happens anywhere else (not even in the bar thread). Why only the foo thread and why only on the cout statement? What about when I decrease/increase the referenced value?
Second, should each thread be using its own mutex? Or is this okay to use a globally shared mutex? What would be the difference between the threads using their own mutex local to their scope rather than a globally shared mutex?
And third, if I have a condition on my threads so they don't run infinitely, why is it that:
cout << "threads done";
gets called after the two threads have finished? The two threads are run asynchronously, no?
Just trying to get a better understanding of this for the future.
I tried it on linux, compiling with g++ -std=c++0x -pthread foo.cpp -o foo and it segfaults here as well.
However, I just tried changing *p++ and *p-- to (*p)++ and (*p)-- and it worked!
The problem is that you're incrementing and decrementing the pointer instead of the value you're pointing to. Try this:
#include <iostream>
using namespace std;
int main() {
int i = 123;
int *p;
p = &i;
cout << *p++ << endl;
cout << *p++ << endl;
cout << *p++ << endl;
cout << *p++ << endl;
cout << *p++ << endl;
}
The output is:
123
-166656888
32767
0
0
Now you'll understand that an access violation means that you're trying to access memory that you can't. Which indicates that you've got a pointer pointing to where you don't want it to.
So when you're doing *p++ you're incrementing the pointer, and not the value. By dereferencing first, by doing (*p), you make sure that it's the value and not the pointer that's changed.