sem_t for pthread on heap

do i understand this right
if i have a class with a class variable
i need to use malloc and cant
do just sem_t sem;
as then sem is created on the stack

1
2
3
4
5
6
7
8
9
10
class X{
sem_t sem; //on stack
}

vs

class X{
sem_t *sem;
x(){
sem = malloc ... //on heap 
I can't understand your question, and perhaps I'm not the only one.
Could you please provide a minimum (nearly) compilable example which reproduces your problem?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
namespace N{
    class A{
    public:
        pthread_t id;
        pthread_t creator;
        int type;
        bool byNew;
        sem_t sem;
        sem_t *sem_p;
        A(int _type) : type(_type){
            creator = pthread_self();
            if(type){
                sem_p = (sem_t*)malloc(sizeof(sem_t));
                sem_init(sem_p, 0, 0);                 
            }else{                
                sem_init(&sem, 0, 0);
            }
            pthread_create(&id, NULL, thread, this);
            
            printf("Creator:%ld ", creator);
            printf("Using malloc %3.3s ", type ? "YES":"NO");
            printf("Using NEW %3.3s ", byNew ? "YES":"NO");
            printf("this thread: %ld", id);
            printf("\n");
        }
        void *operator new(size_t sz) {            
            A *p = (A*)malloc(sizeof(A));
            p->byNew = true;
            return p;
        }
        static void unlock(A *in){
            A *a = (A*)in;
            if(a->type){
                sem_post(a->sem_p);
            }else{
                sem_post(&(a->sem));
            }
            printf("%ld unlocker is same thread %s\n", a->id, (pthread_self() == a->creator) ? "TRUE" : "FALSE");
        }
        static void* thread(void *in){
            A *a = (A*)in;
            if(a->type){
                sem_wait(a->sem_p);
            }else{
                sem_wait(&(a->sem));                
            }
            
            printf("Hallo from %ld\n", a->id);
        }
    };
    class B{
    public:
        A *O0;
        A *O1;
        A *O2;
        A *O3;        
        B(){            
            pthread_t id;
            pthread_create(&id, NULL, thread, this);
        }
        static void* thread(void *in){
            B *b = (B*)in;
            A O0(0);
            b->O0 = &O0;
            A O1(1);
            b->O1 = &O1;
            b->O2 = new A(0);
            b->O3 = new A(1);
            sleep(100000); //prevent O0 O1 to go out of scope
        }
    };
}

    N::A O0(0);
    N::A O1(1);
    N::A *O2 = new N::A(0);
    N::A *O3 = new N::A(1);
    
    N::B b;
    sleep(3); //wait for b to be set up
    
    N::A::unlock(&O0);
    N::A::unlock(&O1);
    N::A::unlock(O2);
    N::A::unlock(O3);
    
    N::A::unlock(b.O0);
    N::A::unlock(b.O1);
    N::A::unlock(b.O2);
    N::A::unlock(b.O3);



sem_init
....
..
If pshared has the value 0, then the semaphore is shared between the
threads of a process, and should be located at some address that is
visible to all threads (e.g., a global variable, or a variable
allocated dynamically on the heap).
...
..


the above code starts 8 threads (+1)
and i get 8 Hallo from...

the documentation extra mentions that "sem" needs to be either a global or dynamically on the heap
sem_t sem;
is neither global nor on the heap if i am not wrong
so is this ubuntu specific that it works regardless
or do i missing something
can some one provide an example where "sem" is created in the wrong way so that the threads are either not unlocked or the program crashes ?


Creator:140411839350592 Using malloc  NO Using NEW  NO this thread: 140411809134336
Creator:140411839350592 Using malloc YES Using NEW  NO this thread: 140411800741632
Creator:140411839350592 Using malloc  NO Using NEW YES this thread: 140411792348928
Creator:140411839350592 Using malloc YES Using NEW YES this thread: 140411783956224
Creator:140411775563520 Using malloc  NO Using NEW  NO this thread: 140411767170816
Creator:140411775563520 Using malloc YES Using NEW  NO this thread: 140411758778112
Creator:140411775563520 Using malloc  NO Using NEW YES this thread: 140411750385408
Creator:140411775563520 Using malloc YES Using NEW YES this thread: 140411674818304
140411809134336 unlocker is same thread TRUE
140411800741632 unlocker is same thread TRUE
140411792348928 unlocker is same thread TRUE
Hallo from 140411809134336
Hallo from 140411792348928
Hallo from 140411783956224
Hallo from 140411800741632
140411783956224 unlocker is same thread TRUE
140411767170816 unlocker is same thread FALSE
140411758778112 unlocker is same thread FALSE
Hallo from 140411767170816
Hallo from 140411750385408
140411750385408 unlocker is same thread FALSE
Hallo from 140411758778112
140411674818304 unlocker is same thread FALSE
Hallo from 140411674818304


Last edited on
First: The encompassing class [X] determines where the member variables are created. So if X is created on the heap sem is also created on the heap.

Second: You shouldn't create two variables where you want just one.

Third: Do not use malloc in C++.

I don't see what you are trying to do with this threads, but you should separte the lock object (mutex) and the data to lock.

can some one provide an example where "sem" is created in the wrong way so that the threads are either not unlocked or the program crashes ?
It is actually not relavant where an object is created. The difference is the life time. On the stack it is limited to the execution of the function while on the heap it is not.

Also See this:
http://www.cplusplus.com/reference/thread/thread/?kw=thread
the above code is just to test it does nothing real

i am just confused on this

1
2
3
and should be located at some address that is
visible to all threads (e.g., a global variable, or a variable
allocated dynamically on the heap)


if it is not relevant why is this extra mentioned in the documentation in what case would it be not on the heap then ??

its obvious that the variable needs to be "alive" at the time i use it
1
2
{sem_t sem}
sem_init(&sem);

wont work
i am just confused on this
The emphasis is placed on "visible to all threads". That is usually done with a global variable. But you are free to do this on the stack in e.g. main(...). Then you need to make sure that the threads end before the memory on the stack is resolved.

You can actually return a pointer to a local variable. This is called a dangling pointer. Which may lead to undefined behavior.

https://en.wikipedia.org/wiki/Dangling_pointer
xeef wrote:
if it is not relevant why is this extra mentioned in the documentation in what case would it be not on the heap then ??

Heap is mentioned as an example (and "heap" doesn't mean "malloc", by the way). There are many safer and more efficient ways to make a variable visible to multiple threads.

xeef wrote:
can some one provide an example where "sem" is created in the wrong way so that the threads are either not unlocked or the program crashes ?

Errors in C++ often lead to undefined behavior. You cannot predict what happens if you make them. Your job as a programmer is to read books and documentation so that you know exactly what everything you write is supposed to do. That said, I am pretty sure you could get EINVAL from sem_post, with some effort.

Consider learning standard C++ multithreading first, it is much simpler to use than POSIX. I am not sure I made sense of your program, with multiple unnecessary classes and allocations, but it seems that it first creates four threads each waiting on its own semaphore until the main thread releases them, and also it makes a thread on which four more threads are launched each waiting on its own semaphore, until the main thread releases them.

Here's how it would look without the noise (just doing the four A threads for reduced redundancy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
#include <semaphore.h>

std::mutex cout_mutex;
struct Sem {
    sem_t sem;
    Sem() { sem_init(&sem, 0, 0); }
    void lock() { sem_wait(&sem); }
    void unlock() {
        {
            std::lock_guard<std::mutex> lk(cout_mutex);
            std::cout << "Unlocker thread is " << std::this_thread::get_id() << '\n';
        }
        sem_post(&sem);
    }
};
struct A : Sem {
    std::thread t{[this]{
        {
          std::lock_guard<std::mutex> lk(cout_mutex);
          std::cout << "This thread:" << std::this_thread::get_id() << '\n';
        }
        lock();
        {
          std::lock_guard<std::mutex> lk(cout_mutex);
          std::cout << "Hallo from " << std::this_thread::get_id() << '\n';
        }
    }};
    ~A() { t.join(); }
};

int main()
{
     std::vector<A> as(4);
     for(auto& a: as) a.unlock();
}

live demo: http://coliru.stacked-crooked.com/a/7d7bf4db08731c50
sample output from that demo:

Unlocker thread is 140273190676288
This thread:140273145829120
This thread:140273154221824
This thread:140273162614528
Unlocker thread is 140273190676288
Unlocker thread is 140273190676288
This thread:140273171007232
Hallo from 140273154221824
Hallo from 140273171007232
Hallo from 140273162614528
Unlocker thread is 140273190676288
Hallo from 140273145829120
Last edited on
just to clarify the above code does nothing real the target was to create a crash
by creating "sem" in a way you should not
what i could not manage
thats why i override the new operator and used malloc and created 2 different
sem vs sem_p

my current conclusion is that this lines from the documentation is meaningless
unless you take extra care in some fancy way that "sem" is not reachable from other threads
maybe thread_local or some thing similar

the main reason for this is i will have a bunch of threads doing some work in some situation they need to outsource parts of their job as it would take to long during which time the thread could not react to new incoming signals
so i will have a threadpool from which they request an extra thread
set up what to do and start the thread (sem_post)
as long i understand its relatively expensive to start a thread so i think its better to reuse them

so "sem" could be created and unlocked from a bunch of different threads thats why i want to understand what they mean by "or a variable
allocated dynamically on the heap"

this is some actual code : (there is an other class managing a list of workers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
namespace XY{
    class WORKER{
        public:            
            WORKER();
            WORKER(const WORKER& orig);
            virtual ~WORKER(); 
            sem_t *thread_sem;  
            void (*job)(void*);
            void *job_obj;
        private:     
            pthread_t thread_id;
            
            static void* thread(void *in);
            
    };
}
XY::WORKER::WORKER(){
    thread_sem = (sem_t*) malloc(sizeof(sem_t)); // as i am not sure 
    //what the documentation says
    sem_init(thread_sem, 0, 0);
    pthread_create(&thread_id, NULL, thread, this);
}

XY::WORKER::~WORKER() {
}
void* XY::WORKER::thread(void *in){
    WORKER *worker = (WORKER*)in;
    do{
        WORKER *worker = (WORKER*)in;
        sem_wait(worker->thread_sem);
        worker->job(worker->job_obj);
        //put it back to the thread pool .....
    }while(1);
}
@coder777

This is called a dangling pointer.


this is clear to me but then you could mention this by ALL thread specific functions
thats why i am confused as it is NOT mentioned by mutex but mentioned by sem_t
that why i was the impression there is something different going on and i need to take extra precaution in some way
Topic archived. No new replies allowed.