Cant pass different strings to multiple threads - multithreading

I have a function that will generate multiple threads and i pass to them a different string every time, but it seems that the threads have the same string. The strings are coming from a socket. Here is the code:
pthread_t *MirrorManager;
MirrorManager = malloc(sizeof(pthread_t)*th_size);
if( MirrorManager == NULL ) { perror("malloc"); exit(1); }
/* -------------------------------------- */
int th_num = 0;
while( true )
{
received = 0;
/* Read the desired readable size */
if( read(newsock, &size, sizeof(size)) < 0 )
{ perror("Read"); exit(1); }
/* Read all data */
while( received < size )
{
if( (nread = read(newsock, buffer + received, size - received)) < 0 )
{ perror("Read"); exit(1); }
received += nread;
}
if( strcmp(buffer, "end") == 0 ) { break; }
printf("Received string: %s\n",buffer);
/* Create thread */
strcpy(th_str, buffer);
if( (err = pthread_create(&MirrorManager[th_num], NULL, thread_start, (void*) th_str)) == true )
{ show_error("pthread_create", err); }
/* Take next thread */
th_num++;
}
Here i generate two threads. The two threads have the same string, actually this string is the last string that will come out of the socket. Why this is happening and how can i prevent this? Please help i have stuck here for a few days now.

You should post the complete code.
Given what you have posted, it looks like your issue is that all of your threads share the same parameter th_str:
pthread_create(&MirrorManager[th_num], NULL, thread_start, (void*) th_str))
Instead you should be allocating a separate th_str for each thread, as you're passing a pointer to it for each thread, rather than the string itself.
th_str = malloc(strlen(buffer));
strcpy(th_str, buffer);
And then be sure to have each thread free the pointer that was passed into it.
PS: I'd strongly recommend using strncmp and strncpy on all data from your socket.

Related

While inserting my kernel module INSMOD exits with error "bad address", warns about "Kernel mismatch"

I am developing this module for custom device that, in fact, a 4*8-bit i-o ports attached to ISA bus with addresses 0x0120 - 0x0123. This driver is based on "scull" by Alessandro Rubini and Jonathan Corbet. My OS is Ubuntu 10.04, kernel is 2.6.32-74 generic, I use built-in console-oriented compiler gcc.
While inserting compiled module using "insmod" I get an error "bad address" and module was not loaded. I've tried to debug it using "printk" and found out that my module successfully gets a range of i-o ports, major and minor numbers and then, when trying to do "Reset_Port" function it generates an error "bad address" and exits.
Can anybody tell me, what am I doing wrong?
Here are __exit and __init functions of my module
void __exit ET3201_exit(void)
{
int i;
dev_t devno = MKDEV(ET3201_major, ET3201_minor);
/* Get rid of our char dev entries */
if (ET3201_devices) {
for (i = 0; i < ET3201_nr_devs; i++) {
ET3201_trim(ET3201_devices + i);
cdev_del(&ET3201_devices[i].cdev);
}
kfree(ET3201_devices);
}
#ifdef ET3201_DEBUG /* use proc only if debugging */
ET3201_remove_proc();
#endif
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, ET3201_nr_devs);
if ( ! port ) release_region(BaseIO, 8);
printk(KERN_INFO "Goodbye, cruel world - ET3201 is unloaded\n");
/* and call the cleanup functions for friend devices */
/*ET3201_access_cleanup();*/
}
/*----------------------------------------------------------------------------*/
/* Set up the char_dev structure for this device. */
static void ET3201_setup_cdev(struct ET3201_dev *dev, int index)
{
int err, devno = MKDEV(ET3201_major, ET3201_minor + index);
cdev_init(&dev->cdev, &ET3201_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &ET3201_fops;
dev->CAMAC_Module_Number = CAMAC_Nmod;
dev->CAMAC_Command_Adress = CAMAC_Adcom;
dev->Driver_Number = ET3201_minor + index;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding ET3201%d", err, index);
}
/*----------------------------------------------------------------------------*/
int __init ET3201_init(void)
{
int result = 0;
int i;
dev_t dev = 0;
BaseIO = Base;
/* Get a range of minor numbers to work with, asking for a dynamic
major unless directed otherwise at load time. */
if (ET3201_major) {
dev = MKDEV(ET3201_major, ET3201_minor);
result = register_chrdev_region(dev, ET3201_nr_devs, "ET3201");
} else {
result = alloc_chrdev_region(&dev, ET3201_minor, ET3201_nr_devs, "ET3201");
ET3201_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "ET3201: can't get major %d\n", ET3201_major);
return result;
}
port = request_region(BaseIO, 8, "ET3201");
if ( port == NULL ) {
printk(KERN_WARNING "ET3201 cannot reserve i-o ports %lu \n", BaseIO);
return -ENODEV;
goto fail;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
ET3201_devices = kmalloc(ET3201_nr_devs * sizeof(struct ET3201_dev), GFP_KERNEL);
if (! ET3201_devices) {
result = -ENOMEM;
printk(KERN_ALERT "ET3201: can't get memory \n");
goto fail; /* Fail gracefully if need be */
}
memset(ET3201_devices, 0, ET3201_nr_devs * sizeof(struct ET3201_dev));
/* Initialize each device. */
for (i = 0; i < ET3201_nr_devs; i++) {
ET3201_devices[i].quantum = ET3201_quantum;
ET3201_devices[i].qset = ET3201_qset;
init_MUTEX(&ET3201_devices[i].sem);
ET3201_setup_cdev(&ET3201_devices[i], i);
}
/* At this point call the init function for any friend device */
dev = MKDEV(ET3201_major, ET3201_minor + ET3201_nr_devs);
/*dev += ET3201_access_init(dev);*/
printk(KERN_INFO "ET3201 is initialized with major %d\n", ET3201_major);
if ( port != NULL ){
printk(KERN_INFO "ET3201 is trying to reset %d devices\n", ET3201_nr_devs);
result = Reset_Port();
}
if ( result != 0 ) {
printk(KERN_ALERT "ET3201: device cannot reset with result %d\n", result);
result = -EFAULT;
goto fail;
}
#ifdef ET3201_DEBUG /* only when debugging */
ET3201_create_proc();
#endif
return 0; /* succeed */
fail:
ET3201_exit();
return result;
}
/*----------------------------------------------------------------------------*/
module_init(ET3201_init);
module_exit(ET3201_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(ET3201_minor);
and next will be Reset_Port()
static int Reset_Port(void)
{
int result = -EIO;
int count;
if (port == NULL) goto fail;
for ( count = 0; count < ET3201_nr_devs; count++ )
{
outb(0x00, ports[count]);
}
wmb(); /*write memory barrier*/
LastOp = E_Reset;
result = 0; /* success */
fail:
return result;
}
EXPORT_SYMBOL(Reset_Port);
Now, after fixing 'int Reset_Port(void)' I've got another problem -
'WARNING: modpost: Found 1 section mismatch(es).'
After debugging I see that this is a result of calling 'ET3201_exit()'
from 'module_init()' - when I remarked this call, warning disappeared.
Surprising that exactly the same call was made in "scull" driver of respected authors - and it works.
Question: What can lead to kernel mismatch in this code?
Yes! The bug is fixed - after declaring ' int Reset_Port(void) ' the module was inserted and removed successfully. I thought,(but it was wrong) that all functions that can be called from within ' module_init() ' must not be declared as static.

How to parse interleaved buffer into distinct multiple channel buffers with PortAudio

hope you can help me :)
I'm trying to get audio data from a multichannel ASIO device with PortAudio library. Everything is ok: I managed to set the default host API as ASIO and I also managed to select 4 specific channels as inputs. Then,I get an interleaved audio stream which sounds correctly but i would like to get each channel data separately.
PortAudio allows to do a non-interleaved recording, but I don't know how to write or modify my RecordCallBack and the multibuffer pointer (one buffer per channel). Sure I've tried... :(
It would be of massive help to me if someone knows how to deal with this issue.
The original RecordCallBack function is taken from a well known stereo example (slightly modified to manage 4 channles instead of 2) but it manages a single interleaved buffer:
static int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
const short *rptr = (const short*)inputBuffer;
short *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS_I];
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
(void) outputBuffer; /* Prevent unused variable warnings. */
(void) timeInfo;
(void) statusFlags;
(void) userData;
if( framesLeft < framesPerBuffer )
{
framesToCalc = framesLeft;
finished = paComplete;
}
else
{
framesToCalc = framesPerBuffer;
finished = paContinue;
}
if( inputBuffer == NULL )
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = SAMPLE_SILENCE; /* ch1*/
if( NUM_CHANNELS_I == 4 ){
*wptr++ = SAMPLE_SILENCE;/* ch2*/
*wptr++ = SAMPLE_SILENCE;/* ch3*/
*wptr++ = SAMPLE_SILENCE;} /* ch4*/
}
}
else
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = *rptr++; /* ch1*/
if( NUM_CHANNELS_I == 4 ){
*wptr++ = *rptr++;/* ch2*/
*wptr++ = *rptr++;/* ch3*/
*wptr++ = *rptr++;} /* ch4*/
}
}
data->frameIndex += framesToCalc;
return finished;
}
The *inputbuffer pointer is declared as:
PaStream* stream;
And the Open_Stream function is called:
err = Pa_OpenStream(
&stream,
NULL, /* no input */
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
playCallback,
&data );
Interleaved just means the bytes for each channel follow after each other as in :
aabbccddeeaabbccddeeaabbccddee (each character represents one byte)
where this input buffer contains two bytes (16 bits) per each of the 5 channels : a, b, c, d & e as it makes 3 repeats across the set of channels which equates to 3 samples per channel ... so knowing input is interleaved, it could be extracted into separate output channel buffers one per channel, but in your code you have just a single output buffer which as you say is due to the necessary callback signature ... one approach would be to write each output channel into the single output buffer separated by distinct offsets per channel so output would be
aaaaaabbbbbbccccccddddddeeeeee
then outside the callback extract out each channel also using same offset per channel
First you need to obtain size of the given output buffer, say X, number of channels, Y, and number of bytes per channel per sample, Z. So global channel offset would be
size_offset = X / (Y * Z) # assure this is an integer
# if its a fraction then error in assumptions
so when addressing output buffer both inside callback and outside we use this offset and knowledge of which channel we are on, W (values 0, 1, 2, 3, ...), and which sample K :
index_output_buffer = K + (W * size_offset) # 1st byte of sample pair
now use index_output_buffer ... then calculate follow-on index :
index_output_buffer = K + (W * size_offset) + 1 # 2nd byte of sample pair
and use it ... you could put above two commands for a given sample into a loop using Z to control number of iterations if Z were to vary but above assumes samples are two bytes
Thank's Scott for your help. The solution was right in front of my eyes and I finally didn't have to work with samples offset. I didn't give you enough information about the code, so your approach was excellent, but the code itself provides an easier way to do that:
The data is storaged in an structrue:
typedef struct
{
int frameIndex; /* Index into sample array. */
int maxFrameIndex;
short *recordedSamples;
}
paTestData;
I modified it to:
typedef struct
{
int frameIndex; /* Index into sample array. */
int maxFrameIndex;
short *recordedSamples;
short * recordedSamples2; //ch2
short * recordedSamples3; //ch3
short *recordedSamples4; //ch4
}
paTestData;
Then I just had to allocate this variables in memory and modified the recordCallback function as follows:
static int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
const short *rptr = (const short*)inputBuffer;
short *wptr = &data->recordedSamples[data->frameIndex];
short *wptr2=&data->recordedSamples2[data->frameIndex];
short *wptr3=&data->recordedSamples3[data->frameIndex];
short *wptr4=&data->recordedSamples4[data->frameIndex];
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
(void) outputBuffer; /* Prevent unused variable warnings. */
(void) timeInfo;
(void) statusFlags;
(void) userData;
if( framesLeft < framesPerBuffer )
{
framesToCalc = framesLeft;
finished = paComplete;
}
else
{
framesToCalc = framesPerBuffer;
finished = paContinue;
}
if( inputBuffer == NULL )
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = SAMPLE_SILENCE; //ch1
if( NUM_CHANNELS_I == 4 ){
*wptr2++ = SAMPLE_SILENCE;//ch2
*wptr3 ++= SAMPLE_SILENCE;//ch3
*wptr4++ = SAMPLE_SILENCE;} //ch4
}
}
else
{
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = *rptr++; //ch1
if( NUM_CHANNELS_I == 4 ){
*wptr2++ = *rptr++;//ch2
*wptr3++ = *rptr++;//ch3
*wptr4 ++= *rptr++;} //ch4
}
}
data->frameIndex += framesToCalc;
return finished;
}
Hope this can help other people. And thank's again, Scott

Make new connections when blocked in a select() call

I have 2 threads:
Thread A:
It's the select() loop. Perform socket handling for reading operations, such as accepting new connections, receiving data.
while (1) {
FD_ZERO(&fdReadSet);
numActiveSockets = 0;
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
numActiveSockets++;
FD_SET(it->first, &fdReadSet);
}
int ret;
bool hasListen = false;
if (( ret = select(numActiveSockets, &fdReadSet, NULL, NULL, NULL)) == SOCKET_ERROR) {
printf("Select Failed, Error code = %d\n", WSAGetLastError());
return -1;
}
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
if (FD_ISSET(it->first, &fdReadSet))
{
if (it->first == TcpSocket::m_listen_sock)
{
if (!hasListen)
{
sockaddr_in sock_addr;
int sockLength = sizeof(sock_addr);
SOCKET sock = accept(it->first, (sockaddr *) &sock_addr, &sockLength);
TcpSocket * socket = new TcpSocket();
socket->m_sock = sock;
m_sock_table[sock] = socket;
it = m_sock_table.begin();
hasListen = true;
}
}
else
{
char * buffer = it->second->GetWriteBuffer();
int numRead = recv(it->first, buffer, SOCKET_BUFFER_SIZE, 0);
if (numRead == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
printf("Connection [%i]: RESET Received. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else
{
printf("Recv Failed. Error code = %d\n", err);
return -1;
}
}
else if (numRead == 0)//connection close
{
printf("Connection [%i]: Graceful exit. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else {
/* Process received data */
}
}
}
}
}
Thread B:
Allow the application to perform connect() to establish new connections. If a connect() is successful, it will the add the returned socket to m_sock_table.
I have a socket table called m_sock_table which holds all the sockets. I use this m_sock_table to initialize the fdReadSet to be used in select().
-----------Problem-----------------
If thread A is blocked by select(), and at the same time thread B establish a new connection through connect(), the application wouldn't be able to receive data from the new connection, because fdReadset has not been updated withed the new connected socket.
What would be a good way to solve this problem? Or the design is just wrong from the start?
You could use a signal that doesn't do anything other than interrupting the system call:
#include <signal.h>
void do_nothing() { }
struct sigaction sa;
sa.sa_handler = do_nothing;
sigemptyset(sa.sa_mask);
#ifdef SA_INTERRUPT
sa.sa_flags = SA_INTERRUPT;
#else
sa.sa_flags = 0;
#endif
sigaction(SIGUSR1, &sa, 0);
Then, in thread B, after starting a new connection, send the signal, after making sure thread A will handle it:
/* need only be done once, but needed in every thread other than A */
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSR1)
pthread_sigmask(SIG_BLOCK, &sigs, 0);
/* each time we create a new connection */
kill(getpid, SIGUSR1);
With the above, select will return with an EINTR error -- so check for that and loop (adding the new connection to the set).

Multi thread Dead Lock - Producer & Customer module using pthread lib

Recently I'm investigate the pthread multi-thread lib and doing some example.
I try to write a Producer-Customer Module: There's a queue to store the Producer's product, and can be get by the Customer.
I set the queue MAX-SIZE as 20. When the queue is full, the Producer thread will wait, until the Customer thread consume one and nofity the Producer thread that he can start produce. And the same as Customer when the queue is empty, the Customer will wait until the Producer thread produce new one and notify him. :-)
I set the Customer thread consume faster than produce, it works fine as the log output in really what I expected. But, when I set the Producer thread consume faster than consume, it seems at last cause a deadlock :-(
I don't kown the reason, can anyone kindly read my code and give me some tips or how to modify the code?
Thanks!
#include "commons.h"
typedef struct tagNode {
struct tagNode *pNext;
char *pContent;
}NodeSt, *PNodeSt;
typedef struct {
size_t mNodeNum;
size_t mNodeIdx;
PNodeSt mRootNode;
}WorkQueue;
#define WORK_QUEUE_MAX 20
static pthread_cond_t g_adder_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t g_adder_mutex = PTHREAD_MUTEX_INITIALIZER;
static WorkQueue g_work_queue = {0};
//------------------------------------------------------------------------
void *customer_thread_runFunc(void *usrdat){
for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex);{
while( g_work_queue.mNodeNum == 0 ) {
pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
}
/********************** CONSUME NEW PRODUCT ***********************/
g_work_queue.mNodeNum --;
if( g_work_queue.mRootNode->pNext != NULL ) {
PNodeSt pTempNode = g_work_queue.mRootNode->pNext;
free( g_work_queue.mRootNode->pContent );
free( g_work_queue.mRootNode );
g_work_queue.mRootNode = pTempNode;
} else {
free( g_work_queue.mRootNode->pContent );
free( g_work_queue.mRootNode );
g_work_queue.mRootNode = NULL;
}
/********************** CONSUME PRODUCT END ***********************/
// Nofity Producer Thread
pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);
// PAUSE FOR 300ms
usleep(300);
}
return NULL;
}
//------------------------------------------------------------------------
void *productor_thread_runFunc( void *usrdat ) {
for( ; ; ) {
pthread_mutex_lock(&g_adder_mutex); {
char tempStr[64];
PNodeSt pNodeSt = g_work_queue.mRootNode;
while( g_work_queue.mNodeNum >= WORK_QUEUE_MAX ) {
pthread_cond_wait(&g_adder_cond, &g_adder_mutex);
}
/********************** PRODUCE NEW PRODUCT ***********************/
g_work_queue.mNodeNum ++;
g_work_queue.mNodeIdx ++;
if( pNodeSt != NULL ) {
for( ; pNodeSt->pNext != NULL; pNodeSt = pNodeSt->pNext );
pNodeSt->pNext = malloc(sizeof(NodeSt));
memset(pNodeSt->pNext, 0, sizeof(NodeSt));
sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
pNodeSt->pNext->pContent = strdup(tempStr);
} else {
g_work_queue.mRootNode = malloc(sizeof(NodeSt));
memset(g_work_queue.mRootNode, 0, sizeof(NodeSt));
sprintf( tempStr, "production id: %d", g_work_queue.mNodeIdx);
g_work_queue.mRootNode->pContent = strdup(tempStr);
}
/********************** PRODUCE PRODUCT END ***********************/
// Nofity Customer Thread
pthread_cond_signal(&g_adder_cond);
}pthread_mutex_unlock(&g_adder_mutex);
// PAUSE FOR 150ms, faster than Customer Thread
usleep(150);
}
return NULL;
}
//------------------------------------------------------------------------
int main(void) {
pthread_t pt1, pt3;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&pt1, &attr, customer_thread_runFunc, NULL);
pthread_create(&pt3, &attr, productor_thread_runFunc, NULL);
pthread_join(pt1, NULL);
pthread_join(pt3, NULL);
printf("MAIN - main thread finish!\n");
return EXIT_SUCCESS;
}
your producer is waiting on the same condition as your consumer? This is definitely a source of trouble. Think about your code conceptually. What preconditions do the producer need before "producing"? As you mentioned, the buffer need to have space.
I did not look in detail, but you probably need an additional condition variable which is used by the producer (not the same as the consumer). The producer wait only if the queue is full. The consumer signal every times it successfully retrieve something from the queue.
EDIT: Reading the doc of pthread lib, One mutex can be used by two conditions
IDEA OF PSEUDOCODE :)
Mutex mqueue
Condition cprod, ccons
produce()
mqueue.lock
while the queue is full
cprod.wait(mqueue)
end
do the production on queue
mcons.signal
mqueue.unlock
end produce
consume()
mqueue.lock
while the queue is empty
ccons.wait(mqueue)
end
do the consumption on the queue
cprod.signal
mqueue.unlock
end consume
Preferably signal when you have the lock. Here I don't think the order make a difference.

Winsock threaded server does not work well when multiple clients connect?

I have a server that spawns a thread for each client that connects to it. The thread then deals with receiving/sending data to the client. Here is my server code:
//////////////
// START //
/////////////
while( 1 )
{
if( listen(serverSocket, SOMAXCONN) == SOCKET_ERROR )
{
printf( "Listen failed with error: %ld\n", WSAGetLastError() );
break;
}
/*
* wait for clients...
*/
clientSocket = accept(serverSocket,
(struct sockaddr *)&clientSockAddr,
&clientSockAddrLen);
if( clientSocket == INVALID_SOCKET )
{
printf("%d:accept failed\n", WSAGetLastError());
closesocket(serverSocket);
WSACleanup();
return 1;
}
printf("Client accepted: IP: %s PORT: %d\n",
inet_ntoa(clientSockAddr.sin_addr),
clientSockAddr.sin_port );
THREADDATA threadData = { clientSocket };
sprintf_s(threadData.ip, "%s", inet_ntoa(clientSockAddr.sin_addr));
// spawn a thread for each client
hthread = CreateThread(
NULL, // don't inherit handle
0, // use default size for the executable
processClient,
(pTHREADDATA)&threadData, // thread data
0, // run right away
&threadId );
}
And here is what my thread function looks like:
/*
called by thread for each client
*/
DWORD WINAPI processClient(LPVOID lpParam)
{
int numBytesRecvd = 0,
numBytesSent = 0,
index = 0,
nLeft = SIZE,
TOTAL = SIZE;
char buff[SIZE];
int run = 1;
char msg[MSG_SIZE];
pTHREADDATA td = (pTHREADDATA)lpParam;
/* keep processing client */
while (run)
{
memset(buff, 0, SIZE);
numBytesRecvd = recv(td->clientSocket, buff, nLeft, 0);
/* CLIENT EXITED */
if( !strcmp(buff, "exit") )
{
printf("Client exited!\n");
run = 0;
}
if( numBytesRecvd > 0 )
{
printf("< %s\n", buff);
}
if (numBytesRecvd == 0)
{
printf("Client closed!\n");
run = 0;
}
if( numBytesRecvd == SOCKET_ERROR )
{
printf("%d:Recieve error!\n", WSAGetLastError());
run = 0;
}
}
closesocket(td->clientSocket);
ExitThread(0);
return 0;
}
Issue:
So I start the server and the client, say client1 (from command prompt in win 7), everything is fine. When I type something at the client1 terminal, it is printed at the server terminal.
Now I launch another client, client2, it gets connected to the server and whatever I type gets displayed at the server, but now when I type something at client1 it doesn't get displayed at the server terminal.
So basically every time I start a new client, only that client can talk to the server, the old clients cannot!!! But I thought the thread will keep handling each client? Or is it that cmd prompt in windows is not thread safe?
I can see two probable issues here : 1) You are passing threadData on the stack to a different thread. You should be allocating it on the heap and then pass it to the thread. 2)I think you are not assigning clientSocket correctly to threadData, shouldnt you be assigning to a member of the structure threadData?

Resources