У вас есть как минимум три условия гонки в вашем коде, где данные используются одним потоком, в то время как они могут быть изменены другим.
Этот код создает условия гонки:
struct message m1[DIM];
struct message m2;
void *func_thread(void *p)
{
int nfd;
nfd= *(int*) p;
int n; //for reading
while(read(nfd,&m2,sizeof(m2))!=0) { //reading
printf("Here is the message: %d from process %d at time %ld %d\n",m2.x, m2.g, m2.timestamp, j);
fflush(stdout);
m1[j]=m2;
j++;
}
pthread_exit(NULL);
}
Каждый поток использует одни и те же структуры данных m1
и m2
, перезаписывая данные друг друга при чтении в m2
.Они также одновременно обновляют j
, поэтому его значение нельзя доверять ни одному из потоков.
Кроме того, вы не представляете, сколько байт вы действительно прочитали.
Этокод создает другую гонку данных:
while(i<2) {
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
iret1 = pthread_create(&id[i], NULL, func_thread, &newsockfd);
if (iret1) {
perror("pthread_create");
return -1;
}
i++;
}
Объедините это с
void *func_thread(void *p)
{
int nfd;
nfd= *(int*) p;
, и дочерний поток обращается к newsockfd
из основного потока, но newsockfd
может иметь другое значениек тому времени, когда дочерний поток получает к нему доступ.
Лучший способ:
struct message m1[DIM];
int j = 0
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *func_thread(void *p)
{
// each thread needs its own struct
struct message m2;
// pass the socket by **value**
int nfd = ( intptr_t ) p;
for ( ;; )
{
// don't put code that needs error checks inside conditions
// because you can't handle errors, nor in this case partial
// read results
ssize_t bytes_read = read( nfd, &m2, sizeof( m2 ) );
if ( bytes_read == 0 )
{
break;
}
// really should put code here to handle a partial read()
printf("Here is the message: %d from process %d at time %ld %d\n",
m2.x, m2.g, m2.timestamp, j);
fflush(stdout);
// another race condition if this isn't mutex'd
pthread_mutex_lock( &mutex );
// get a local copy of the current value of j so
// the structure assignment can be moved outside
// the mutex-locked critical section
int my_j = j;
j++;
pthread_mutex_unlock( &mutex );
// stay within the bounds of the array
if ( my_j >= DIM )
{
break;
}
m1[my_j]=m2;
}
pthread_exit(NULL);
}
Обратите внимание, что newsockfd
теперь передается значением , а не адресом, поэтомуpthread_create()
вызов должен быть:
iret1 = pthread_create(&id[i], NULL, func_thread, ( void * )( intptr_t ) newsockfd);
Это что-то вроде хака, который основан на способности вашей платформы передавать значение int
, такое как newsockfd
, как void *
, но как угодносистема, которую вы сейчас используете, почти наверняка сможет это сделать.