this is a simple program I've been working on that listens to a socket, and starts a new thread to handle each connection to said socket.
In my while loop I get a Segmentation Fault, that has something to do with pthread_create (if I comment that line out the program loops properly). My knowledge of pointers is mediocre at best, and debugging with gdb didn't yield anything of value. This is gdb's output:
#0 0x0000000000000000 in ?? ()
#1 0x000000080064f4f1 in pthread_getprio () from /lib/libthr.so.3
#2 0x0000000000000000 in ?? ()
Error accessing memory address 0x7fffffbff000: Bad address.
The program gets through the while loop once successfully, and properly receives and responds to a connection at the socket, but then before getting into the second while loop, the program fails on a Segmentation Fault error.
Here's a condensed version of my program:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <pthread.h>
#define UNIX_PATH_MAX 100
#define SOCK_PATH "/tmp/demo_socket"
/*===============> CONNECTION HANDLER FUNCTION <=================*/
void *connection_handler(int connection_fd)
{
int nbytes;
char buffer[256];
nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;
printf("\tMESSAGE FROM CLIENT: %s\n", buffer);
nbytes = snprintf(buffer, 256, "Hello from the server!");
write(connection_fd, buffer, nbytes);
close(connection_fd);
return;
}
/*==========================> MAIN <=============================*/
int main(void)
{
struct sockaddr_un addr; //socket address information
int sock_fd, conn_fd; //socket file descriptors
socklen_t addr_len = sizeof(struct sockaddr_un); //size of sockaddr_un structure
pid_t child_pid; //pid holder
pthread_t thread; // thread identifier
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0)
return 1;
unlink(SOCK_PATH);
memset(&addr, 0, addr_len);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); // Copies up to sizeof(addr.sun_path)-1 bytes from SOCK_PATH into addr.sun_path
printf("> Socket sun_family = %d (AF_UNIX), Socket sun_path = %s ...\n", addr.sun_family, addr.sun_path);
/*----------------------FAIL CHECKS-------------------------*/
if (bind(sock_fd, (struct sockaddr *) &addr, addr_len) != 0)
return 1;
if (listen(sock_fd, 5) != 0)
return 1;
printf("> Listening to socket bound at %s ...\n\n", SOCK_PATH);
/*--------------------WHILE LOOP----------------------------*/
while ( (conn_fd = accept(sock_fd, (struct sockaddr *) &addr, &addr_len)) > -1) {
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
printf("> Closing connection at %d inside server process ...\n", conn_fd);
close(conn_fd);
printf("> Reached bottom of loop!\n");
}
/*---------------------------FIN------------------------------*/
close(sock_fd);
unlink(SOCK_PATH);
printf("> Socket closed and unlinked from path ... Done!\n ");
return 0;
}
Any help would be greatly appreciated!
This is wrong:
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
pthread_create requires the address of the function to run in the new thread. What your code does is call connection_handler in the main thread and then pass the result of connection_handler to pthread_create as the function address.
What you need is the following:
pthread_create(&thread , NULL, connection_handler, (void*)conn_fd);
You'll also need to change connection_handler to take void* instead of int:
void *connection_handler(void* arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
}
Your usage of pthread_create is incorrect. the third argument should be a pointer to a function of type void *(*start_routine) (void *), instead you are passing the return of connection_handler.
Change connection_handler to receive a void * argument (and make sure it returns an actual value), eg.
#include <stdint.h>
void *connection_handler(void *arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
return NULL;
}
and change your call to something like the following
pthread_create(&thread, NULL, &connection_handler, (void *)conn_fd);
You should also make sure to either start the thread detached, detach the thread with pthread_detach or join it later with pthread_join
buffer[nbytes] = 0;
This will overflow if you've read 256 bytes. Increase buffer size or decrease read size by one.
Most likely because you are closing the socket connection in two places. There is good chance that in one run of the thread its not yet got around to the write but in your parent thread already closed the connection.
Why do you need to create so many threads? Wouldn't one worker thread suffice? you can pile up the jobs on to this worker thread...
Related
I am trying to create an HTTP server using multi-threading. main() hands off the client_sock from accept() to one of the worker threads. If no worker threads are available, it waits until one is. I am restricted to not being able to call accept() within the worker threads. Here is a portion of my code so far. Some questions I have are:
Do I need to use 2 pthread mutex and condition variables as I do right now?
Do I need to use pthread lock or unlock at all in these cases?
If I wanted to add a mutex lock when files are being created on the server, would I have to create another mutex variable or would one of the existing ones work?
#include <iostream>
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <getopt.h>
#include <pthread.h>
#define SIZE 1024
struct shared_data
{
int redundancy;
int client_sock;
int working_threads;
int dispatch_ready;
pthread_mutex_t* dispatch_mutex;
pthread_mutex_t* worker_mutex;
pthread_cond_t* dispatch_cond;
pthread_cond_t* worker_cond;
};
void* receiveAndSend(void* obj)
{
struct shared_data* data = (struct shared_data*) obj;
int bytes;
char buff[SIZE + 1];
while(1)
{
while(!data->dispatch_ready)
{
pthread_cond_wait(data->dispatch_cond, data->dispatch_mutex);
}
data->dispatch_ready = 0;
data->working_threads++;
client_sock = data->client_sock;
bytes = recv(client_sock, buff, SIZE, 0);
// do work
data->working_threads--;
pthread_cond_signal(data->worker_cond);
}
}
int main(int argc, char* argv[])
{
if(argc < 2 || argc > 6)
{
char msg[] = "Error: invalid arg amount\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
char* addr = NULL;
unsigned short port = 80;
int num_threads = 4;
int redundancy = 0;
char opt;
while((opt = getopt(argc, argv, "N:r")) != -1)
{
if(opt == 'N')
{
num_threads = atoi(optarg);
if(num_threads < 1)
{
char msg[] = "Error: invalid input for -N argument\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
}
else if(opt == 'r')
{
redundancy = 1;
}
else
{
// error (getopt automatically sends an error message)
return 1;
}
}
// non-option arguments are always the last indexes of argv, no matter how they are written in the terminal
// optind is the next index of argv after all options
if(optind < argc)
{
addr = argv[optind];
optind++;
}
if(optind < argc)
{
port = atoi(argv[optind]);
}
if(addr == NULL)
{
char msg[] = "Error: no address specified\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = getaddr(addr);
serv_addr.sin_port = htons(port);
int serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if(serv_sock < 0)
{
err(1, "socket()");
}
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
{
err(1, "bind()");
}
if(listen(serv_sock, 500) < 0)
{
err(1, "listen()");
}
// Connecting with a client
struct sockaddr client_addr;
socklen_t client_addrlen;
pthread_mutex_t dispatch_mutex;
pthread_mutex_init(&dispatch_mutex, NULL);
pthread_mutex_t worker_mutex;
pthread_mutex_init(&worker_mutex, NULL);
pthread_cond_t dispatch_cond;
pthread_cond_init(&dispatch_cond, NULL);
pthread_cond_t worker_cond;
pthread_cond_init(&worker_cond, NULL);
struct shared_data data;
data.redundancy = redundancy;
data.dispatch_ready = 0;
data.working_threads = 0;
data.dispatch_mutex = &dispatch_mutex;
data.worker_mutex = &worker_mutex;
data.dispatch_cond = &dispatch_cond;
data.worker_cond = &worker_cond;
pthread_t* threads = new pthread_t[num_threads];
for (int i = 0; i < num_threads; i++)
{
pthread_create(&threads[i], NULL, receiveAndSend, &data);
}
while(1)
{
data.client_sock = accept(serv_sock, &client_addr, &client_addrlen);
while(data.working_threads == num_threads)
{
pthread_cond_wait(data.worker_cond, data.worker_mutex);
}
data.dispatch_ready = 1;
pthread_cond_signal(data.dispatch_cond);
}
return 0;
}
There are many very basic bugs in your program, which pretty clearly demonstrate that you don't understand locks and condition variables (or appropriate use of pointers).
A lock protects some shared data. You have exactly one shared data item, therefore you should need exactly one lock (mutex) to protect it.
A condition variable indicates that some condition is true. Reasonable conditions for your use case would be worker_available and work_available. (Naming your condition variables dispatch_cond and worker_cond does not help clarity.)
A condition variable is always associated with a mutex, but you don't need two separate mutexes just because you have two condition variables.
On to the bugs.
This code is obviously buggy:
while(1)
{
while(!data->dispatch_ready)
{
pthread_cond_wait(data->dispatch_cond, data->dispatch_mutex);
}
From man pthread_cond_wait:
atomically release mutex and cause the calling thread to block on the condition variable cond
How can this thread release a mutex if it never acquired it?
Also, how can this thread read data->dispatch_ready (shared with other threads) without acquiring a mutex?
This code:
struct shared_data data;
data.redundancy = redundancy;
data.dispatch_ready = 0;
data.working_threads = 0;
data.dispatch_mutex = &dispatch_mutex;
data.worker_mutex = &worker_mutex;
data.dispatch_cond = &dispatch_cond;
data.worker_cond = &worker_cond;
isn't buggy, but has unnecessary indirection. You could make dispatch_mutex and condition variables be part of shared_data, like so:
struct shared_data
{
int redundancy;
int client_sock;
int working_threads;
int dispatch_ready;
pthread_mutex_t dispatch_mutex;
pthread_mutex_t worker_mutex;
pthread_cond_t dispatch_cond;
pthread_cond_t worker_cond;
};
And here is the most subtle bug I noticed:
data.client_sock = accept(serv_sock, &client_addr, &client_addrlen);
...
data.dispatch_ready = 1;
pthread_cond_signal(data.dispatch_cond);
Here, you will wake up at least one of the threads waiting for dispatch_cond, but may wake up more than one. If more than one thread is awoken, they all will proceed to recv on the same client_sock with potentially disastrous results.
Update:
How do I fix this.
Probably the best and most performant way to fix this is to have a queue of "work items" (using e.g. a double-linked list with head and tail pointers), protected by a lock.
Main thread would add elements at the tail (while holding a lock), and signal "not empty" condition variable.
Worker threads would remove head element (while holding a lock).
Worker threads would block on "not empty" condition variable when queue is empty.
Main thread may continue adding elements when queue is full (all workers are busy), or it may block waiting for a worker to become available, or it can return "429 too many requests" to the client.
I am practicing different forms of causing a server to run concurrently by being able to accept multiple responses from multiple clients. This is a school assignment.
I am now having troubles with threading. The thread works but gets an error of
"curl: (56) Recv failure: Connection reset by peer"
This is because of the line in the response function that my thread goes to. Rest assured all variables besides clients[n] are pretty much constants. So its rather not passing in right or I'm completely missing the mark on how threading should be done.
rcvd = recv(clients[n], mesg, 99999, 0);
which this line keeps returning -1 into rcvd and I want > 0.
Here is my code.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include<pthread.h>
#include "functions.h"
#define CONNMAX 1000
#define BYTES 1024
char *ROOT;
int verbose;
int signalReceived = 1;
int listenfd, clients[CONNMAX], slot;
pthread_t thread;
void error(char *);
void *threadServer(void *arg)
{
printf("bong");
respond(slot, verbose, ROOT, clients);
exit(0);
}
void clean(int arg)
{
signalReceived = 0;
}
int main(int argc, char *argv[])
{
signal(SIGINT, clean);
signal(SIGHUP, clean);
struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
char PORT[6];
ROOT = getenv("PWD");
strcpy(PORT, "8888");
while ((c = getopt (argc, argv, "p:v")) != -1)
switch (c)
{
case'v':
verbose = 1;
break;
case'p':
strcpy(PORT, optarg);
break;
case'?':
fprintf(stderr, "Wrong arguments given\n");
exit(1);
default:
exit(1);
}
printf("Listening on port %s%s%s, root is %s%s%s\n", "\033[92m", PORT, "\033[0m", "\033[92m", ROOT, "\033[0m");
int i = 0;
for (i = 0; i < CONNMAX; i++)
clients[i] = -1;
startServer(PORT, &listenfd);
while (signalReceived == 1)
{
addrlen = sizeof(clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot] < 0)
exit(0);
else
{
printf("bang");
pthread_create(&thread, NULL, threadServer, NULL);
}
while (clients[slot] != -1)
slot = (slot + 1) % CONNMAX;
}
return 0;
}
I am learning and this is not my original source work, rather an edited work in order to learn. I took a forked original program and am now trying to convert it to a threaded program.
slot is a global variable. Starting a thread can take a little while, and threads share the same memory. They don't have their own snapshots of it like a forked process does.
After starting the thread, your main process alters slot.
Best case scenario: new thread starts and gets the new value of slot such that connections[slot] == -1. Worst case: the thread runs on a different CPU core and gets slot while main is writing to it, resulting in a bad value.
You might want to consider passing slot as a parameter to the thread function instead:
void *threadServer(void *arg)
{
int mySlot = (int)arg;
printf("bong\n");
respond(mySlot, verbose, ROOT, clients);
clients[mySlot] = -1;
printf("bash\n");
return NULL; // calling 'exit' terminates the whole process. duh.
}
// ...
pthread_create(&thread, NULL, threadServer, (void*)slot);
Another issue you have here is that you create all these threads but you do not keep track of them individually. You probably need an array of threads, or you might want to consider a simple struct:
typedef struct Clients {
int fd;
pthread_t thread;
} Clients;
Clients clients[MAXCONN];
//
while (signalReceived == 1)
{
addrlen = sizeof(clientaddr);
clients[slot].fd = accept(listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot].fd < 0)
exit(0);
else
{
printf("bang");
pthread_create(&clients[slot].thread, NULL, threadServer, (void*)slot);
}
while (clients[slot] != -1)
slot = (slot + 1) % CONNMAX; // what if we can't find one?
}
Your threadServer function calls exit, terminating the process.
I'm not sure where that came from, since it wouldn't be appropriate in a server that calls fork either. But it's definitely fatal in a multi-threaded program.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am testing out my code for reconnection in case the connection drop. However I'm facing some Segmentation Error after the socket is re-opened and re-connected.
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h> //socket
#include <bluetooth/bluetooth.h> //bluetooth
#include <bluetooth/rfcomm.h> //bluetooth
#include <string.h> //strlen
#include <arpa/inet.h> //inet_addr
struct BTConnection {
int client;
int s;
int retry;
};
struct BTConnection bt_1;
void *bt_connect(void *arg);
void *bt_send(void *arg);
void *bt_receive(void *arg);
void *bt_connect(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
socklen_t opt = sizeof(rem_addr);
// allocate socket
connect->s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 1;
bind(connect->s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(connect->s, 1);
// accept one connection
connect->client = accept(connect->s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
return 0;
}
void *bt_send(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
char buf[1024] = { 0 };
int bytes_read, retry;
puts("[Bluetooth] Sending data to device...");
while(1) {
.....
pthread_mutex_lock(&mDataMutex);
puts("send mutex in");
while(connect->retry != 0);
puts("send mutex out");
pthread_mutex_unlock(&mDataMutex);
if(write(connect->client, return_msg, strlen(return_msg)) < 0) {
....
puts("Error reading from socket");
pthread_mutex_lock(&mDataMutex);
puts("send mutex");
if(connect->retry == 0)
connect->retry = 2;
pthread_mutex_unlock(&mDataMutex);
puts("send mutex end");
pthread_mutex_lock(&mDataMutex);
if(connect->retry == 2) {
close(connect->client);
close(connect->s);
bt_connect(&connect);
connect->retry = 0;
puts("send retry success");
} else
retry = 1;
pthread_mutex_unlock(&mDataMutex);
if(retry == 1)
{
puts("bluetooth send retrying in 8 secs");
sleep(8);
}
} else
retry = 0;
// clear buffer
memset(return_msg,0,sizeof return_msg);
memset(temp,0,sizeof temp);
// set to send data every second
sleep(1);
}
return 0;
}
void *bt_receive(void *arg)
{
// similar as above
}
int main(void)
{
bt_1.retry = 0;
int rc;
void *status;
pthread_t bt_connect_thread, bt_send_thread, bt_receive_thread;
pthread_attr_t attr;
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Create BT connect thread and start it
rc = pthread_create(&bt_connect_thread, &attr, bt_connect, (void *)&bt_1);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
return (-1);
}
rc = pthread_join(bt_connect_thread, &status);
rc = pthread_create(&bt_send_thread, &attr, bt_send, (void *)&bt_1);
rc = pthread_create(&bt_receive_thread, &attr, bt_receive, (void *)&bt_1);
rc = pthread_join(bt_send_thread, &status);
rc = pthread_join(bt_receive_thread, &status);
close(bt_1.client);
close(bt_1.s);
pthread_attr_destroy(&attr);
return 0;
}
The code may look a little messy in sending and receiving part as I was using mutex to check and debug the output.
This is the output I am getting:
[Bluetooth] Allocating socket... Done!
[Bluetooth] Bind socket... Done!
[Bluetooth] Waiting for incoming connections...
[Bluetooth] Accepted connection from 44:6D:6C:6D:1B:BC
[Bluetooth] Bluetooth connection thread completed
[Bluetooth] Receiving data from device...
rcv mutex in
rcv mutex out
[Bluetooth] Sending data to device...
send mutex in
send mutex out
send mutex in
send mutex out
[Bluetooth-Receive] Error reading from socket
receive mutex
receive mutex end
[Bluetooth-Receive] Connections closed. Reconnecting...
[Bluetooth] Allocating socket... Done!
[Bluetooth] Bind socket... Done!
[Bluetooth] Waiting for incoming connections...
[Bluetooth] Accepted connection from 44:6D:6C:6D:1B:BC
[Bluetooth] Bluetooth connection thread completed
Segmentation fault
I am not sure what is wrong since I did ensure that i close the socket before re-opening it. Any help/guidance? Thanks!
Edit: Not sure if bt_send is jamming it since it didn't print out [Bluetooth-Send] Error reading from socket when I'm sending test data automatically every second... (and both send and receive are running simultaneously)
PS. New to C and Socket Programming
void *bt_connect(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
Okay, so we need to call bt_connect passing it a pointer to a BTConnection.
struct BTConnection *connect = (struct BTConnection*)arg;
...
bt_connect(&connect);
Since connect is a pointer to a BTConnection, &connect is a pointer to a pointer. So why are we passing it to bt_connect?
Here is the threaded-server code in C. My question is: do we need to set unused thread to NULL? In java, we need to set thread to NULL to let it return to thread pool.
I made the change to Martin Broadhurst's source code (see gray text as comment)
/*
* A threaded server
* by Martin Broadhurst (www.martinbroadhurst.com)
* Compile with -pthread
*/
#include <stdio.h>
#include <string.h> /* memset() */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT "32001" /* Port to listen on */
#define BACKLOG 10 /* Passed to listen() */
void *handle(void *pnewsock)
{
/* send(), recv(), close() */
return NULL;
}
int main(void)
{
int sock;
pthread_t thread;
struct addrinfo hints, *res;
int reuseaddr = 1; /* True */
/* Get the address info */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(NULL, PORT, &hints, &res) != 0) {
perror("getaddrinfo");
return 1;
}
/* Create the socket */
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
perror("socket");
return 1;
}
/* Enable the socket to reuse the address */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) {
perror("setsockopt");
return 1;
}
/* Bind to the address */
if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
perror("bind");
return 0;
}
freeaddrinfo(res);
/* Listen */
if (listen(sock, BACKLOG) == -1) {
perror("listen");
return 0;
}
/* Main loop */
while (1) {
pthread_attr_t *attr; //<===I added this
size_t size = sizeof(struct sockaddr_in);
struct sockaddr_in their_addr;
int * ptr; //<===I added this
ptr = malloc(sizeof(int)); //<===I added this
ptr = accept(sock, (struct sockaddr*)&their_addr, &size);
if (newsock == -1) {
perror("accept");
}
else {
printf("Got a connection from %s on port %d\n",
inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
//I added the following "if" statement
if (pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED) != 0){
fprintf(stderr, "Failed to set thread detached\n");
}
else {
//if (pthread_create(&thread, NULL, handle, &newsock) != 0) {
if (pthread_create(&thread, attr, handle, ptr) != 0 ) {
fprintf(stderr, "Failed to create thread\n");
}
}
}
}
close(sock);
return 0;
}
==========-==============
code is from here:
http://martinbroadhurst.com/source/threaded-server.c.html
No. Well, it's not 100% clear what Java construct it is you're thinking of (I bet there's a close method you can call instead of setting it to null and having the GC take care of it), but that's irrelevant because...
pthread_t is an integer (maybe) type, not a pointer, so it can't be set to NULL.
C is not garbage collected, so even if it were a pointer the thread would have no way of knowing or caring that you set it to null.
POSIX threads does not use a thread pool. The pthread_create function actually creates a brand-new OS-level thread, and returning from the handler actually exits it. (Well, not really. It still hangs around until you call pthread_join, since you didn't create it as a detached thread.)
What you should do is create the threads as detached threads, since your code right now is leaking joinable threads.
Also, using &newsock as the argument is dangerous, since it gets destroyed and recreated in every iteration of the main loop. This is a race condition that probably never showed up in the author's testing because under light load the main thread would be waiting for the next accept to return while it is accessed on the worker thread, and on most systems the same space will be used over and over for the variable.
You can use malloc to create a place to store the socket fd in (which you will need to free at the end of your handler function), or, if your platform allows this (most do), just cast the value to a pointer then cast it back out in the handler function.
Since C doesn't have objects, there is no object that represents the thread and so nothing to set to NULL. A detached thread will go away when it terminates. An undetached thread will go away when it's joined.
You have a pthread_t as thread id, there is no object, and it don't work in the way as java gc.
Thread terminate in 1 of following cases:
its start function return,
the thread call pthread_exit()
canceled by pthread_cancel()
any of threads in the process call exit(),
the main thread returns,
in this case, all threads in the process will terminate immediately,
I'm having a segmentation fault problem with a networking program using threads to deal with each new connection.
MAX_PEERS is defined above as 10.
...
int iret[MAX_PEERS];
pthread_t thread[MAX_PEERS];
(void) signal(SIGCHLD, reaper);
printf("before while\n");
int i = 0;
while(1) {
if(i>MAX_PEERS-1){break;}
client_len = sizeof(client);
new_sd = accept(sd, (struct sockaddr *)&client, &client_len);
if(new_sd < 0){
fprintf(stderr, "Can't accept client \n");
exit(1);
}
printf("before thread\n");
iret[i] = pthread_create(&thread[i], NULL, connection, (void*) new_sd);
if(iret != 0){
printf("thread[%d] not generated!\n", i);
}
i++;
printf("end of while\n");
}
....
and the function "connection" beggins as follows
void *connection(void *sdd)
{
int sd =* (int *) sdd;
...
When the client tries to connect to the server I get a segmentation fault.
> ./server 20011
before while
before accept
after accept
before thread
./server: zsh: segmentation fault ./server 20011
>
It prints "before accept" before the client connects, and after the client connects it prints the rest.
Am I creating the threads correctly? Any ideas?
Thanks,
accept() returns an integer, so new_sd must be an integer. When you create a new thread you cast new_sd to a void pointer. But when you get that pointer in the function, instead of casting back to int you cast it to a pointer to int and dereference it, which causes the seg fault.
Instead of using possibly incorrect casting, rather pass an integer. Assuming that new_sd will go out of scope, allocate space for an integer and pass it to your thread.
int* new_sdp = malloc( sizeof( *new_sdp )) ;
*new_sdp = new_sd ;
iret[i] = pthread_create(&thread[i], NULL, connection, new_sdp);
and in the thread:
void *connection(void *sdd)
{
int sd = *(int *)sdd;