Pass variable into pthread_create function - c

I'm building a multi-threaded network chat program, but I can't figure out how to pass variables into pthread_create.
I have the following line of code that creates a thread:
pthread_create(&thread, NULL, receive, (void *) socket_fd);
My receive function looks like this:
void * receive(void * socket) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
socket_fd = (int) socket;
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
}
}
}
How can I pass a prompt variable into this receive function, when calling receive in pthread_create?

You can pack all of the data you want to pass to your thread on creation in a single struct and pass its pointer through the last parameter of pthread_create. in short:
define a struct:
typedef struct{
char* prompt;
int socket;
} thread_data;
and then call pthread_create:
thread_data data;
// place code here to fill in the struct members...
pthread_create(&thread, NULL, receive, (void *) &data);
in your receive function:
void * receive(void * threadData) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
thread_data* pData = (thread_data*)threadData;
socket_fd = pData->socket;
char* prompt = pData->prompt;
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
}
}
}
Hope this helps.

Related

Reduce overhead in mutex

I am learning mutex currently and the following is the test code. It works perfectly fine. It creates another instance after one is done. Yet, it also introduces overhead according to here.
How efficient is locking an unlocked mutex? What is the cost of a mutex?. How can I modify my code to improve the efficiency?
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct _context_t {
uint64_t id;
char *name;
bool initialized;
} context_t;
context_t *ctx = NULL;
context_t *get_instance() {
pthread_mutex_lock(&lock);
if (ctx == NULL) {
ctx = (context_t *)malloc(sizeof(context_t));
assert(ctx != NULL);
ctx->initialized = false;
}
pthread_mutex_unlock(&lock);
return ctx;
}
int id = 0;
void *do_work(void *arg) {
context_t *ctx = get_instance();
if (!ctx->initialized) {
ctx->name = (char *)arg;
ctx->id = ++id;
ctx->initialized = true;
}
printf("name=%s\tid=%ld\n", ctx->name, ctx->id);
return NULL;
}
int main() {
int rc;
pthread_t p1, p2;
rc = pthread_create(&p1, NULL, do_work, "A");
assert(rc == 0);
rc = pthread_create(&p2, NULL, do_work, "B");
assert(rc == 0);
rc = pthread_join(p1, NULL);
assert(rc == 0);
rc = pthread_join(p2, NULL);
assert(rc == 0);
if (ctx) {
free(ctx);
}
return 0;
}
Instead of having two threads racing to create the context_t, you should create it once before the threads start, and pass its address to the threads explicitly.
Note that you can pass multiple arguments via pthread_create() by putting them in a struct and passing its address.
Then you won't need a mutex at all, because the threads will only read from ctx rather than potentially writing to it.

DBus: Watch when name disappears from bus

I am implimenting the StatusNotifierWatcher service using the low-level DBus C library. The StatusNotifierWatcher specification requires that the watcher can know when "A StatusNotifierItem instance has disappeared from the bus" So that it can send the StatusNotifierItemUnregistered signal.
An example implimentation:
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
DBusConnection *conn = NULL;
void item_unregistered_signal(const char *name) {
DBusMessage *signal = dbus_message_new_signal(
"/org/freedesktop/StatusNotifierWatcher",
"org.freedesktop.StatusNotifierWatcher",
"StatusNotifierItemUnregistered");
dbus_message_append_args(signal,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
dbus_connection_send(conn, signal, NULL);
dbus_message_unref(signal);
}
void watch_name(const char *name, void(*cb)(const char *)) {
// Not sure how to impliment
}
dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
DBusError error;
char *name;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error parsing method args: %s\n", error.message);
return FALSE;
}
watch_name(name, item_unregistered_signal);
return TRUE;
}
static void check_and_abort(DBusError *error) {
if (dbus_error_is_set(error)) {
fprintf(stderr, "dbus_err: %s\n", error->message);
exit(EXIT_FAILURE);
}
}
int main() {
DBusError error;
dbus_error_init(&error);
conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
check_and_abort(&error);
dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, register_item, NULL, free);
while(1) {
dbus_connection_read_write_dispatch(conn, 1000);
}
}
If I have the well-known name to a DBus service, how do I know when the name disappears from the bus?
Well, I figured this out and I'll post an answer for any future poor souls who need to work with libdbus.
org.freedesktop.DBus sends the NameOwnerChanged signal whenever any DBus name changes. One can use this signal to track if an item has disappeared because the NewOwner argument is a null string.
This function can do that:
static DBusHandlerResult signal_handler(DBusConnection *connection,
DBusMessage *message, void *_usr_data) {
if (dbus_message_is_signal(message, "org.freedesktop.DBus",
"NameOwnerChanged")) {
const char *name;
const char *old_owner;
const char *new_owner;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error getting OwnerChanged args");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (strcmp(name, "") != 0) {
// Name not lost, just swapped owners
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
name_lost(name);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
One also needs to add a match so that your program will be called with this signal. I added this in main()
dbus_bus_add_match(conn,
"type='signal',\
sender='org.freedesktop.DBus',\
interface='org.freedesktop.DBus',\
member='NameOwnerChanged'",
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, signal_handler, NULL, free);
For those using GDBus (recommended) instead of libdbus (discouraged), the equivalent is g_bus_watch_name().

Logs thread in C

Here is my problem ! I want to make a log Thread. But the buffer between the writer thread and the reader thread don't seems to work.
The buffer is in the:
typedef struct{
char *bufLog;
pthread_mutex_t mutex;
} sLog;
sLog* globalLog;
The reader thread read permanently the buffer and print what is it inside on the screen.
void* lireLog(void *param_l){
while(1){
pthread_mutex_lock(&(globalLog->mutex));
if(strlen(globalLog->bufLog) > 0)
printf("Log: %s\n", globalLog->bufLog);
pthread_mutex_unlock(&globalLog->mutex);
}
return 0;
}
And the writer thread write into the buffer.
void *otherThread(){
while(1){
ecrireLog("salut");
}
}
void* ecrireLog(char *text){
pthread_mutex_lock(&(globalLog->mutex));
memcpy(globalLog->bufLog, text, strlen(text));
pthread_mutex_unlock(&(globalLog->mutex));
return 0;
}
And there is the main()
int main(int argc, char *argv[]){
globalLog->bufLog = (char*) malloc(sizeof(char*)*255);
res = pthread_mutex_init(&(globalLog->mutex), NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
//creation du thread log
res = pthread_create(&log_t, NULL, lireLog, NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
res = pthread_create(&other_t, NULL, otherThread, NULL);
if (res) {fprintf(stderr, "create %s", strerror(res));exit(1);}
pthread_join(log_t, NULL);
pthread_join(other_t, NULL);
}
Thanks ! :)

Passing structures in pthread

I am trying to pass a structure when creating a thread but does not seem to work correctly!
Here is the structure:
struct analyse_data {
int verbose; //should be 1 or 0
};
Note that verbose can only be 1 or 0 and nothing else.
Here is the method being called (note it can be called multiple times by another method):
void dispatch(struct pcap_pkthdr *header, const unsigned char *packet,
int verbose) {
static bool thread_settings_initialised = false;
printf("Verbose: %d\n", verbose); //Prints 1 or 0
//Only run the first time dispatch method runs
if (thread_settings_initialised == false){
thread_settings_initialised = true;
//...
//Set mutex for the appropriate variables to remain thread safe
//...
//Set attr so threads are "Detached"
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//Set pthread_cond_init
//...
}
//Put parameters into a struct so can be sent in a thread
struct analyse_data data;
data.verbose = verbose;
//...
pthread_t tid;
printf("data.verbose: %d\n", data.verbose); //This prints 1 or 0
int rc = pthread_create( &tid, &attr, bar, (void *) &data);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
and this is the method thats being called by the thread:
void analyse(void *thread_data) {
struct analyse_data *data;
data = (struct analyse_data *) thread_data;
int verbose = data->verbose;
printf("Verbose = %d\n", verbose ); //Prints weird numbers like -547845...
}
As you can see from my comments, the value of verbose changes when being used inside the method. Why? What am I doing Wrong?
Many Thanks!
Update (thanks to JS1)
I updated my code to use a pointer:
void dispatch(struct pcap_pkthdr *header, const unsigned char *packet,
int verbose) {
static bool thread_settings_initialised = false;
printf("Verbose: %d\n", verbose); //Prints 1 or 0
//...
//Put parameters into a struct so can be sent in a thread
struct analyse_data *data = malloc(sizeof(struct analyse_data)); //NEW
data->verbose = verbose;
//...
pthread_t tid;
printf("data.verbose: %d\n", data.verbose); //This prints 1 or 0
int rc = pthread_create( &tid, &attr, bar, (void *) data);
//...
}
But now the analyse() method always outputs 0, even when verbose is 1!
You should not pass a stack variable to pthread_create. Notice that data is local to the function dispatch and will be out of scope when dispatch returns. You should instead either use malloc to allocate data, or use a static or global variable.
If you use the malloc method, it will look like this:
struct analyse_data *data = malloc(sizeof(struct analyse_data));
data->verbose = verbose;
int rc = pthread_create( &tid, &attr, bar, data);
You must remember to not call free on data from dispatch. The memory should "belong" to the thread, so you should eventually call free on data from the thread when you are done using the contents of data.

Using a String array in a thread function

I'm trying to pass an array to thread function so that it has access to the array in the function. For the moment it just contains the name of the threads.
const char *a[2];
char *s = "Thread 1";
char *r = "Thread 2";
a[0] = s;
a[1] = r;
pthread_create(&t, NULL, oddhandler, (void *)a[0]);
pthread_create(&y, NULL, evenhandler, (void *)a[1]);
The intention is to write the create like this
pthread_create(&t, NULL, oddhandler, &a);
pthread_create(&y, NULL, evenhandler, &a);
How would I re-write this function to accommodate this change?
static void *
oddhandler(void *p)
{
char *q = (char *)p;
printf("%s is ready.\n", q);
sigset_t set;
int sig = SIGUSR1;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
while (1) {
/* Wait for SIGUSR1 */
sigwait(&set, &sig);
printf("%s received a SIGUSR1!\n", q);
}
return ((void *)NULL);
}
You could try coupling the thread id with the thread data :
typedef struct thread_info {
int thread_id; // different for every thread
void * thread_data; // the same for every thread
}
As in your example program, you could create one function, handler, and have threads adjust based on their id.
pthread_create(&(t[id], NULL, handler, &(info[i]));
void * handler(void * info) {
thread_info * myInfo = (thread_info *) info;
char *q = ((char *) myInfo->thread_data) + myInfo->thread_id;
// rest of function
}

Resources