I am a complete beginner in OS. The problem I am having is that I want to receive a value from a thread into the main process. A garbage value is printed in the main. Please elaborate so I can know my mistake.
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include<string.h>
#include <sys/wait.h>
#include<pthread.h>
#include <sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<time.h>
#include <fstream>
#include<vector>
using namespace std;
void *thread_1(void *arg);
int main(int argc, char* argv[])
{
void *temp;
pthread_t t1;
pthread_create(&t1, NULL,thread_1,NULL);
pthread_join(t1,&temp);
int *num = (int*)temp;
cout<<"Value in main: "<<*num<<endl;
}
void *thread_1(void *arg)
{
int number = 5;
int* value = &number;
cout<<"Value in thread: "<<*value<<endl;
pthread_exit((void*)value);
}
You have two ways to do this:
Pass a pointer to an integer as the argument to the thread, and have the thread modify the argument to hold the value you want.
Have the thread allocate a value on the heap and return a pointer to that memory. Then clean it up later.
#include <iostream>
#include <pthread.h>
void *thread_1(void *arg);
void *thread_2(void *arg);
int main(int argc, char* argv[])
{
int value = 0;
pthread_t t1;
pthread_create(&t1, NULL,thread_1, &value);
pthread_join(t1, NULL);
std::cout<<"Value in main: "<<value<<std::endl;
int* value2 = NULL;
pthread_t t2;
pthread_create(&t2, NULL,thread_2, NULL);
pthread_join(t2, reinterpret_cast<void**>(&value2));
if (value2) {
std::cout<<"Value in main: "<<*value2<<std::endl;
delete value2;
}
}
void *thread_1(void *arg)
{
int* value = static_cast<int*>(arg);
*value = 5;
std::cout<<"Value in thread: "<<*value<<std::endl;
pthread_exit(NULL);
}
void *thread_2(void *arg)
{
int* value = new int(10);
std::cout<<"Value in thread: "<<*value<<std::endl;
pthread_exit(static_cast<void*>(value));
}
Try:
void *thread_1(void *arg)
{
int value = *((int *)arg);
cout<<"Value in thread: "<<value<<endl;
int new_val = 345;
pthread_exit(&new_val );
}
int main(int argc, char* argv[])
{
int *temp=15;
void *return_val;
pthread_t t1;
pthread_create(&t1, NULL,thread_1,(void *)temp);
pthread_join(t1,&return_val);
cout<<"Value in main: "<<*temp<<endl;
cout<<"Value from loop: "<<*(int*)return_val<<endl;
}
More info: http://www.cse.cuhk.edu.hk/~ericlo/teaching/os/lab/9-PThread/Pass.html
Related
I had download Google breakpad source to do some testing, the demo can work normal on X64 and ARM64, but on MIPS64 it does not generate minidump file and child thread will crash after sys_clone under ExceptionHandler::GenerateDump();
I checked the input address of the child thread, found the address is reduced by 16 bytes, my kernel revision is :
[root#neo7 breakpad-master]# uname -r
3.10.0-514.26.2.ns7.030.mips64el
My test code is :
#include "../src/client/linux/handler/exception_handler.h"
#include <pthread.h>
#include <iostream>
using namespace std;
static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded)
{
printf("Dump path: %s\n", descriptor.path());
char cmd[512] = {0};
snprintf(cmd, sizeof(cmd), "echo %s > dump_name", descriptor.path());
system(cmd);
return succeeded;
}
void *TestThread(void* arg)
{
int input = *(int*)arg;
int *a = (int *)(NULL);
*a = 1;
}
int main(int argc, char *argv[])
{
google_breakpad::MinidumpDescriptor descriptor("/tmp");
google_breakpad::ExceptionHandler eh(descriptor,
NULL,
dumpCallback,
NULL,
true,
-1);
//crashHare();
pthread_t threadId;
int input = 12;
int ret = pthread_create(&threadId, NULL, TestThread, (void*)&input);
if(ret != 0)
{
cout<< "create thread error"<<endl;
}
cout<<"main thread running"<<endl;
pthread_join(threadId,NULL);
return 0;
}
I add some printf in ./src/client/linux/handler/exception_handler.cc, before sys_clone and after ThreadEntry, the log is :
struct ThreadArgument {
pid_t pid; // the crashing process
const MinidumpDescriptor* minidump_descriptor;
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.minidump_descriptor = &minidump_descriptor_;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
zzzzzzz &thread_arg:f10ee460 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 23889
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:f10ee450 (child thread)
if the type of thread_arg is a int *, there is no address offset problem. If add prefix static for thread_arg, there is no address offset problem too.
static ThreadArgument thread_arg; /* The same goes for malloc, but malloc is not safe */
zzzzzzz &thread_arg:20030060 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 22399
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:20030060 (child thread)
And I write an another code to test sys_clone under signal processing function:
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <ucontext.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "src/third_party/lss/linux_syscall_support.h"
#include "src/common/memory_allocator.h"
using namespace google_breakpad;
unsigned char *stack = NULL;
void my_memset(void* ip, char c, size_t len) {
char* p = (char *) ip;
while (len--)
*p++ = c;
}
struct ThreadArgument {
pid_t pid; // the crashing process
const void* minidump_descriptor;
void* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
int ThreadEntry(void *arg) {
printf("arg:%x\n", arg);
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
printf("thread_arg:%x\n", thread_arg);
return 0;
}
void GenerateDump(int signo) {
static const unsigned kChildStackSize = 16000;
PageAllocator allocator;
uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
if (!stack)
return ;
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = (void *) NULL;
thread_arg.minidump_descriptor = (void *) NULL;
thread_arg.pid = getpid();
thread_arg.context = (void *) NULL;
thread_arg.context_size = sizeof(void *);
printf("thread_arg:%x\n", &thread_arg);
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
printf("child:%d\n", child);
sleep(1);
return ;
}
int main(void)
{
signal(SIGSEGV, GenerateDump);
int *a = (int *)NULL;
*a = 1;
return 0;
}
It works normal:
thread_arg:ffcb9030
child:8447
arg:ffcb9030
thread_arg:ffcb9030
I wonder why passing the contents of the stack as parameters causes this
address mismatch problem in breakpad.
I'm following this application by my book, and I tried to copy this program and see what it does.
With my big surprise I found that it doesn't work!!
The program is the following:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <time.h>
#define TANTI 10
int parametroOUT;
void* codice(void *arg){
srand(time(NULL));
parametroOUT=(rand()%6)+1;
pthread_exit((void*)¶metroOUT);
}
int main(){
int dadoEstratto, *risultato=0;
pthread_t t1;
pthread_create(&t1,NULL,codice,NULL);
pthread_join(t1, (void*) &risultato);
printf("dado estratto: %d",*risultato);
return 0;
}
It returns an error at the line: pthread_join(t1, (void*) &risultato);.
The error is:
[Error] invalid conversion from 'void*' to 'void**' [-fpermissive]
How can I fix this error?
This code is wrong:
int *risultato=0;
...
pthread_join(t1, (void*) &risultato);
The prototype for pthread_join() is:
int pthread_join(pthread_t thread, void **value_ptr);
Note that it's a void **. That's because the function used to start a thread returns a void *. To be able to access the void * returned from the thread-start function, you need to pass the address of a void * so that pthread_join() can fill in the value:
void *risultato=0;
...
pthread_join(t1, &risultato);
Note that risultato is now the proper void *, and it's address is passed to pthread_join() by using the & "address-of" operator.
To get back to the int return value from your codice() function:
int *intPtr = ( int * ) risultato;
int value = *intPtr;
The second argument should have type void**.
Here's what you should do:
void *risultato_voidp;
pthread_join(t1, &risultato_voidp);
resultato = static_cast<int*>(risultato_voidp);
Full example:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <time.h>
#include <errno.h>
#define TANTI 10
int parametroOUT;
void* codice(void *arg){
srand(time(NULL));
parametroOUT=(rand()%6)+1;
pthread_exit(static_cast<void*>(¶metroOUT));
}
int main(){
int dadoEstratto, *risultato=0;
void *risultato_voidp;
pthread_t t1;
int er;
if(0!=(er=pthread_create(&t1,NULL,codice,NULL))) return errno=er,perror(0),1;
pthread_join(t1, &risultato_voidp);
risultato = static_cast<int*>(risultato_voidp);
printf("dado estratto: %d\n",*risultato);
return 0;
}
I solved my problem by making this simple function, thank you to everyone who helped me
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <time.h>
#define TANTI 10
int dadi[TANTI];
int i=0;
void* codice(void *arg){
while(i<TANTI){
srand(time(NULL);
dadi[i]=rand() % 6 + 1;
printf("il dado estratto e': %d\n",dadi[i]);
i++;
}
pthread_exit(0);
}
int main(){
int dadoEstratto;
pthread_t t1;
pthread_create(&t1,NULL,codice,NULL);
pthread_join(t1,NULL);
return 0;
}
As I came to know creating and terminating thread abruptly
using pthread_kill() everytime is not a good way to do, so I am going
with suspend and resume method for a thread using thread1.suspend() and
thread1.resume(), whenever needed. How to do/implement this?
Take below LED blinking code for reference. During thread1.start() creating thread with suspended = false; is continuing as it is stuck in a while loop.
Calling thread1.suspend() has no effect.
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
bool suspended;
int fd;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;
void start() {
suspended = false;
pthread_create(&threadID, NULL, led_Flash, (void*)this );
}
PThread(int fd1) { this->fd=fd1; }
~PThread() { }
void suspend() {
pthread_mutex_lock(&m_SuspendMutex);
suspended = true;
printf("suspended\n");
do {
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
} while (suspended);
pthread_mutex_unlock(&m_SuspendMutex);
}
void resume() {
/* The shared state 'suspended' must be updated with the mutex held. */
pthread_mutex_lock(&m_SuspendMutex);
suspended = false;
printf("Resumed\n");
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
};
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int ret=0;
int fd= pt->fd;
while(pt->suspended == false)
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
return NULL;
}
int main()
{
int fd1=1,fd2=2, fd3=3;
class PThread redLED(fd1);
class PThread amberLED(fd2);
class PThread greenLED(fd3);
redLED.start();
amberLED.start();
greenLED.start();
sleep(1);
redLED.suspend();
return 0;
}
Could some body help me, please?
After a little modification of above code , it seems working . Thanks guy for pointing out issues on above code, the changes are as follow.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<iostream>
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
volatile int suspended;
int fd;
pthread_mutex_t lock;
PThread(int fd1)
{
this->fd=fd1;
this->suspended =1; //Initial state: suspend blinking untill resume call
pthread_mutex_init(&this->lock,NULL);
pthread_create(&this->threadID, NULL, led_Flash, (void*)this );
}
~PThread()
{
pthread_join(this->threadID , NULL);
pthread_mutex_destroy(&this->lock);
}
void suspendBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 1;
pthread_mutex_unlock(&this->lock);
}
void resumeBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 0;
pthread_mutex_unlock(&this->lock);
}
};
void gpio_write(int fd, int value)
{
if(value!=0)
printf("%d: on\n", fd);
else
printf("%d: off\n", fd);
}
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int fd= pt->fd;
while(1)
{
if(!(pt->suspended))
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
}
return NULL;
}
int main()
{
//Create threads with Initial state: suspend/stop blinking untill resume call
class PThread redLED(1);
class PThread amberLED(2);
class PThread greenLED(3);
// Start blinking
redLED.resumeBlink();
amberLED.resumeBlink();
greenLED.resumeBlink();
sleep(5);
// suspend/stop blinking
amberLED.suspendBlink();
sleep(5);
redLED.suspendBlink();
sleep(5);
amberLED.suspendBlink();
sleep(5);
redLED.resumeBlink();
pthread_exit(NULL);
return 0;
}
I start to use pthread of C++ and have made a simple exampe for multi threads(3). But what i see is that I always got prints from two threads. why?
#include <iostream>
#include <string>
#include <pthread.h>
using namespace std;
int N=10;
void* run(void* arg) {
char* msg = (char*)arg;
for(int i; i<=N; ++i) std::cout<<msg<<std::endl;
}
int main(int argc, char* argv[]) {
if (argc > 1) N = stoi(argv[1]);
pthread_t t1,t2,t3;
pthread_create(&t1,NULL,run,(void*)"xxx");
pthread_create(&t2,NULL,run,(void*)" howdy");
pthread_create(&t3,NULL,run,(void*)" wrold");
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
return 0;
}
Prints like:
howdy
wrold
howdy
wrold
It's undefined behaviour, anything can happen.
For example on my machine it doesn't print anything at all.
i is not initialized.
void* run has to return something (e.g.: return NULL;)
Only one consumer works fine, but multiple consumers will crash, I am wondering why.
#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include <queue>
using namespace std;
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_qs_notempty = PTHREAD_COND_INITIALIZER;
pthread_cond_t g_qs_notfull = PTHREAD_COND_INITIALIZER;
queue<string> qs;
void *
producer(void *arg)
{
static vector<string> vs{"a ","b ","c ","d ","e "};
static int idx = 0;
while(1){
pthread_mutex_lock(&g_mutex);
if(qs.size()==5)//full
pthread_cond_wait(&g_qs_notfull,&g_mutex);
qs.push(vs[idx]);
idx = (idx+1)%5;
pthread_cond_signal(&g_qs_notempty);
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
void *
consumer(void *arg)
{
while(1){
pthread_mutex_lock(&g_mutex);
if(qs.empty())
pthread_cond_wait(&g_qs_notempty,&g_mutex);
cout<<qs.front();
qs.pop();
pthread_cond_signal(&g_qs_notfull);
pthread_mutex_unlock(&g_mutex);
}
return NULL;
}
int main()
{
struct thread_info *tinfo;
pthread_attr_t attr;
pthread_t thread_id;
pthread_attr_init(&attr);
pthread_create(&thread_id, &attr, &producer, 0);
pthread_create(&thread_id, &attr, &consumer, 0);
pthread_create(&thread_id, &attr, &consumer, 0); //adding this line will crash
pthread_exit(0);
}
It is not guaranteed that _signal() wakes up only a single thread.
So you must recheck your condition upon wakeup. A simply way to fix your code is to switch the if for while.