How to use pthread to modify pointers in main process? - c

In the sample below, I tried to modify a char pointer in the main process using pthread. However, I dont see the pointer value changed. What is the reason and how can I achieve my goal?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //Header file for sleep(). man 3 sleep for details.
#include <pthread.h>
#include <errno.h>
#include <string.h>
char *target = "thread";
void *modify(void *vargp) {
vargp = target;
printf("Thread vargp = %s\n", (char*)vargp);
return NULL;
}
int main() {
char *pt = "main";
pthread_t thread_id;
printf("Before Thread, pt = %s\n", pt);
pthread_create(&thread_id, NULL, modify, pt);
pthread_join(thread_id, NULL);
printf("After Thread, pt = %s\n", pt);
exit(0);
}
$ ./pthread_simple
Before Thread, pt = main
Thread vargp = thread
After Thread, pt = main
What I want to achieve is:
$ ./pthread_simple
Before Thread, pt = main
Thread vargp = thread
After Thread, pt = thread

Function arguments are copies of what are passed and change to them is local to the functions. To have functions modify things, you have to pass pointers to what should be modified.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //Header file for sleep(). man 3 sleep for details.
#include <pthread.h>
#include <errno.h>
#include <string.h>
char *target = "thread";
void *modify(void *vargp) {
*(char**)vargp = target; /* add cast and dereference to modify what is pointed */
printf("Thread vargp = %s\n", *(char**)vargp); /* add cast and dereference */
return NULL;
}
int main() {
char *pt = "main";
pthread_t thread_id;
printf("Before Thread, pt = %s\n", pt);
pthread_create(&thread_id, NULL, modify, &pt); /* pass pointer to pt */
pthread_join(thread_id, NULL);
printf("After Thread, pt = %s\n", pt);
exit(0);
}

Related

How to get a pthread name in C

Say I create a pthread as pthread_t lift_3; and pthread_create(&lift_1, NULL, lift, share);. When it goes into lift(), how can I get it the function to print the actual name of the thread? Or set a name for the thread?
I have tried using pthread_self() to acquire the id, but it instead gives random numbers
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* lift(void* ptr)
{
printf("thread name = %c\n", pthread_self());
pthread_exit(NULL);
return NULL;
}
int main()
{
pthread_t lift_1; // declare thread
pthread_create(&lift_1, NULL, lift, NULL);
pthread_join(lift_1, NULL);
return 0;
}
The expected outcome should be thread name = lift_1
You're looking for the "name of the function that the thread started in".
There is no such thing as "thread name".
When calling pthread_self, you get the "id" of the thread, which something like a randomly-generated name.
To simulate the desired behavior in the past, I wrote the following code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// This lines means a variable that is created per-thread
__thread const char* thread_name;
void* lift(void* ptr)
{
// Paste this line in the beginning of every thread routine.
thread_name = __FUNCTION__;
// Note two changes in this line
printf("thread name = %s\n", thread_name);
pthread_exit(NULL);
return NULL;
}
int main()
{
// Added line
thread_name = __FUNCTION__;
pthread_t lift_1; // declare thread
pthread_create(&lift_1, NULL, lift, NULL);
pthread_join(lift_1, NULL);
//Added line
printf("Original thread name: %s\n", thread_name);
return 0;
}

reading and writing int from/to shared memory in c

I'm trying to make a program where a thread writes an integer into a shared memory location and then the other thread reads and prints that integer. the problem I'm facing is that the second thread keeps reading the integer as -1.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
struct args {
void* memptr;
sem_t* semptr;
};
void *p1(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
//sem_wait(semaphore);
//sleep(0.5);
for(int i=0; i<=10; i++)
{
if (!sem_wait(semaphore)) {
printf("got in if p1\n");
sprintf(memory, "%d", i);
sem_post(semaphore);
sleep(1);
}
}
if (!sem_wait(semaphore)) {
sprintf(memory, "%d", 0);
sem_post(semaphore);
sleep(1);
}
sleep(0.1);
}
void *p2(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
sleep(0.1);
while(1)
{
if (!sem_wait(semaphore)) {
printf("got in if p2\n");
if((int)memory == 0){
break;
}
printf("%d\n", (int)memory);
sem_post(semaphore);
sleep(1);
}
}
}
const int ByteSize = 4;
const char* SharedName = "memNameTest";
const char* SemaphoreName = "semNameTest";
int main()
{
int fd = shm_open(SharedName, O_RDWR, 0644);
ftruncate(fd, ByteSize);
void* memptr = mmap(0, ByteSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sem_t* semptr = sem_open(SemaphoreName, O_CREAT, 0644, 0);
sem_post(semptr);
struct args *Share = (struct args *)malloc(sizeof(struct args));
Share->memptr = memptr;
Share->semptr = semptr;
pthread_t thread1, thread2;
printf("Before Thread\n");
pthread_create(&thread1, NULL, p1, (void*)Share);
pthread_create(&thread2, NULL, p2, (void*)Share);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("After Thread\n");
munmap(memptr, ByteSize);
close(fd);
sem_close(semptr);
unlink(SharedName);
return 0;
exit(0);
}
I have tried changing (int)memory into *((int*)memory) but that resulted in a segmentation error.
(edit)
as suggested I tried this in a single-threaded program and got it to work as follows:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
/* the size (in bytes) of shared memory object */
const int SIZE = 4;
/* name of the shared memory object */
const char* SharedName = "memoryInt";
/* create the shared memory object */
int shm_fd = shm_open(SharedName, O_CREAT | O_RDWR, 0644);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
void* memptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=1; i<=10; i++){
/* write to the shared memory object */
//sprintf(memptr, "%d", i);
memcpy(memptr, &i, sizeof(int));
printf("%d\n", *((int*)memptr));
sleep(1);
}
return 0;
}
though this still doesn't work in a multi-threaded program as i get a segmentation fault.
this is the output:
Before Thread
got in if p1
Segmentation fault
First, you have to show what happen on your terminal when you compile your program.
Secondly, the function sprintf has the declaration:
sprintf(char *str, const char *format, ...);
That means the p1 will write the null terminated string of character. In your code, i dont understand why you use the void pointer memory instead of using char pointer as the description. You should verify the read/write function by using single-threaded before applying to the multi-thread.

Detached threads don't run simultaneously

Hey so I'm trying to create a multithreaded program. The first thread takes in input from std in and stores it in a minheap. The second thread... well for now, all it does is print "sequencer thread works" and nothing else because it doesn't run properly.
Both threads are detached, so they should run simultaneously, and yet for some reason the second thread doesn't run until the first exits. Is it something simple I am overlooking? I'm new to multithreading.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include "MinHeap.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* readerthread(MinHeap minheap, char eventlist[], char timestamp[])
{
char buffer[100];
char input;
int ret, len, fd;
while(1)
{
char *choice;
choice = malloc(50*sizeof(char));
fgets(choice, 50, stdin);
printf("choice = : %s", choice);
if(checkTimestamp(choice)==0)
{
pthread_mutex_lock(&mutex);
addElement(&minheap, choice);
pthread_mutex_unlock(&mutex);
}
free(choice);
printf( "min of minheap: %s\n", getMin(&minheap));
}
void* sequencerthread()
{
printf("sequencer works\n");
fflush(stdout);
pthread_exit(0);
}
int main(int argc, char *argv[])
{
if (argv < 2)
{
printf("not enough arguments. exiting...\n");
return 1;
}
char timestamp[50];
char event[50];
char eventlist[sizeof(char)+170];
int i;
char nowtimestamp[] = "2400/001/00/00/00";
MinHeap minheap;
initializeMinHeap(&minheap, intCompare, sizeof(char)*50);
strcpy(timestamp, argv[1]);
strcpy(event, argv[2]);
pthread_t ignore1, ignore2;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&ignore1, &attr, readerthread(minheap, eventlist, nowtimestamp), 0);
pthread_create(&ignore2, &attr, sequencerthread, 0);
pthread_attr_destroy(&attr);
pthread_exit(0);
return (EXIT_SUCCESS);
}
This line is the problem:
pthread_create(&ignore1, &attr, readerthread(minheap, eventlist, nowtimestamp), 0);
You're calling readerthread on the main thread and passing its result to pthread_create. Since readerthread never returns, you never even get to the first call to pthread_create, let alone the second one.
You need to call it like this instead:
pthread_create(&ignore1, &attr, readerthread, &readerthread_args);
where readerthread_args is a struct encapsulating the arguments to pass to readerthread. You'll also need to change readerthread to take a single void * argument, cast it to the type of readerthread_args, and unpack the args.
You should have got a whole bunch of warnings from your compiler. Did you remember to turn them on?

clang bug on pthread with ucontext on mac

I am using ucontext along with pthread. The below program works OK on Linux, but has failed assertion on Mac.
The problem seems that thread local variables are not correctly accessed after resuming the context from another thread.
The program creates two threads, A and B. A sets the context ready before B could resume the context, for it's synced properly.
It's very appreciated if someone could shed some light on this behavior on mac.
ENV:
clang version 3.7.0 (http://llvm.org/git/llvm.git 8d70064a4ac2ae09b8003173e751cfad9dc15400)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
Program:
#define _XOPEN_SOURCE 800
#include <ucontext.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
static int flag = 0;
void swap(ucontext_t *old, ucontext_t *new)
{
int ret = swapcontext(old, new);
assert(ret == 0);
}
#define SSIZE MINSIGSTKSZ
static char stack[SSIZE];
static ucontext_t a_ctx[2];
static ucontext_t b_ctx[2];
volatile static __thread int bug = 0;
static void func(int b) { }
static void f1 (void)
{
assert(bug == 0);
func(bug);
swap(&a_ctx[1], &a_ctx[0]);
assert(bug == 1);
}
void *thread_a(void *arg)
{
printf("A is %lu\n", pthread_self());
bug = 0;
ucontext_t ctx = a_ctx[1];
getcontext(&ctx);
ctx.uc_stack.ss_sp = stack;
ctx.uc_stack.ss_size = sizeof stack;
makecontext(&ctx, f1, 0);
swap(&a_ctx[0], &ctx);
__atomic_store_n(&flag, 1, __ATOMIC_RELAXED);
sleep(1);
return NULL;
}
void *thread_b(void *arg)
{
printf("B is %lu\n", pthread_self());
bug = 1;
while(__atomic_load_n(&flag, __ATOMIC_RELAXED) == 0) ;
swap(&b_ctx[0], &a_ctx[1]);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t a, b;
pthread_create(&b, NULL, &thread_b, NULL);
pthread_create(&a, NULL, &thread_a, NULL);
pthread_exit(NULL);
}

string argument in thread function

I'm having problems passing a string to a thread function using pthread_create
I get strange charactes when i run the progam
here is the code
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/stat.h>
#define NTHREADS 3
void *myFun(void *ptr){
char * string;
string = (char *) ptr;
printf("string: %s\n", string);
return NULL;
}
int main(int argc, char *argv[]){
pthread_t threads[NTHREADS];
char* thread_args[NTHREADS];
int i;
char* string;
/* spawn threads */
for (i=0; i<NTHREADS; ++i){
string = "file1.txt";
thread_args[i] = string;
if(pthread_create(&threads[i], NULL, myFun, (void *) &thread_args[i]) != 0){
printf("Error creating thread\n");
exit(1);
}
}
/* Wait for threads to finish */
for (i=0; i<NTHREADS; ++i) {
pthread_join(threads[i], NULL);
}
return 0;
}
I can pass a int without problems doing a cast to int in the same way i did in the code, but with char it is not working.
Pass the pointer, not the address of the pointer.
if(pthread_create(&threads[i], NULL, myFun, (void *) thread_args[i])
^

Resources