2016-11-05 4 views
0

Мне нужно написать программу для класса, которая создает 8 потоков. 4 производителя и 4 потребителя. Производителям необходимо зацикливать и произвольно отправлять SIGUSR1 или SIGUSR2 ко всем потребительским потокам. Только 2 должны зарегистрироваться, если они получили SIGUSR1 и другие 2 регистра SIGUSR2.Создаются нити, затем все выходят до критической области

Когда я пытаюсь запустить его, все потоки создаются, «готовый продукт» печатается всеми 4 потоками производителей, «ожидание 1» печатается обоими потоками, но «ожидание 2» печатается 3 раза, после чего все потоки выходят , В конце отладки говорится, что процесс завершается нормально.

Мне нужно использовать семафоры для управления критическими областями. Любая помощь будет большой.

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <signal.h> 

#define NP 4 
#define NC1 2 
#define NC2 2 
#define CNT 10 

void handler1(int signum); 
void handler2(int signum); 

typedef struct { 
    int sent; 
    int received; 
    int buf[1]; 
    int SIG1;    
    int SIG2;    
    sem_t con;   
    sem_t prod;   
} sbuf_t; 

sbuf_t buff; 

void *producer() { 
    printf("prod ready \n"); 
    int s; 
    while(1){ 
     sem_wait(&buff.prod); 
     s=rand()%2; 
     if(s==1){ 
      buff.sent++; 
      kill(0,SIGUSR1); 
     } 
     else if(s==2){ 
      buff.sent++; 
      kill(0,SIGUSR2); 

     }sem_post(&buff.prod); 
    } 

} 

void *consumer1() { 
    signal(SIGUSR1, handler1); 
    printf("waiting 1\n"); 
    while(1){ 

    } 
} 

void *consumer2() { 
    signal(SIGUSR2, handler2); 
    printf("waiting 2\n"); 
    while(1){ 

    } 
} 

void handler1(int signum){ 
    if(signum==SIGUSR1){ 
     sem_wait(&buff.con); 
     printf("Caught 1\n"); 
     buff.received++; 
     buff.SIG1++; 

     sem_post(&buff.con); 
    } 
} 

void handler2(int signum){ 
    if(signum==SIGUSR2){ 
     sem_wait(&buff.con); 
     printf("caught 2 \n"); 
     buff.received++; 
     buff.SIG2++; 

     sem_post(&buff.con); 
    } 
} 

void main(){ 
    pthread_t threads[9]; 
    buff.SIG1=0; 
    buff.SIG2=0; 
    buff.sent=0; 
    buff.received=0; 
    int index; 


     sem_init(&buff.con, 0, 0); 
    sem_init(&buff.prod, 0, 0); 
    for (index = 0; index < NP; index++) { 
      pthread_create(&threads[index], NULL, producer,NULL); 
     } 
     for (index = 0;index < NC1;index++) { 
      pthread_create(&threads[index+4], NULL, consumer1,NULL); 
     } 
    for (index = 0;index < NC2;index++) { 
      pthread_create(&threads[index+6], NULL, consumer2,NULL); 
     } 
} 
+0

для удобства чтения и понимания: 1) последовательно отступать код. Отступ после каждой открывающей скобки '{'. unindent перед каждой закрывающей скобкой '}'. Предложите использовать 4 пробела для каждого уровня отступов, так как это видно даже с переменной шириной шрифта. Никогда не используйте вкладки для отступов, так как каждый текстовый процессор/редактор имеет ширину табуляции/ширину закладки, установленную по-разному. 2) отдельные блоки кода (для if, else, while, do ... while, switch, case, default) через пустую строку. – user3629249

+0

Независимо от того, что Visual Studio позволит вам уйти; функция main() 'имеет только две действительные сигнатуры:' int main (void) 'и' int main (int argc, char * argv []) 'I.E. все они имеют тип возврата 'int'. – user3629249

+0

Когда код выполняет сравнение между литералом и чем-либо еще для равенства, всегда помещайте литерал слева, поэтому любая ошибка ключевого слова, такая как использование '=', а не '==', будет улавливаться компилятором, а не тратить часы и часы и получение седых волос над простой ошибкой клавиш. – user3629249

ответ

-1

Для примера, вы создаете своих производителей перед своими потребителями. Также у вашего продюсера вы используете генератор случайных чисел, чтобы определить, выдаете ли вы USR1 или USR2. Ваше описание создавало впечатление, что вы хотели два из них (по сравнению с некоторым случайным смешиванием в сумме 4), что я вижу, что код делает для вас.

+0

Я хочу, чтобы 2 потока отвечали каждому USR1 и USR2, но это случайный случай, который выпускает производитель. Что вы подразумеваете под комбинацией на общую сумму 4? Разве не должно быть, чтобы производители проходили через петлю, из-за семафора, и бежали до тех пор, пока она не прекратится с терминала, потому что это то, что я хочу, чтобы это делалось? Извините, если я недостаточно описателен, но я новичок в потоках и сигналах. Также, когда я запускаю его с помощью GDB, он выходит с кодом 0377. –

+0

это не отвечает, почему все выходит (почти) сразу, что и задается вопросом. так что это плохой ответ. – user3629249

0

В функции main(), нити создаются,

затем main() выходы.

Когда main() выходит, все потоки также выходят.

Предложите чтение о таких функциях, как: pthread_exit() и pthread_join()

Примечания: Следующий имеет ошибку в обработке сигналов, а также в обработке семафоров, но демонстрируют использование pthread_join() и pthread_exit()

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <signal.h> 

#define NP 4 
#define NC1 2 
#define NC2 2 
#define CNT 10 

#define MAX_THREADS (9) 

void handler1(int signum); 
void handler2(int signum); 

struct sbuf_t 
{ 
    int sent; 
    int received; 
    int buf[1]; 
    int SIG1;    
    int SIG2;    
    sem_t con1; 
    sem_t con2;   
    sem_t prod;   
}; 

typedef struct sbuf_t myData; 
myData buff; 

void *producer(void *dummy) 
{ 
    (void)dummy; 

    printf("prod ready \n"); 
    int s; 

    while(1) 
    { 
     sem_wait(&buff.prod); 
     s=rand()%2; 

     if(!s) 
     { 
      buff.sent++; 
      kill(0, SIGUSR1); 
     } 

     else // if(s) 
     { 
      buff.sent++; 
      kill(0, SIGUSR2); 
     } 

     //sem_post(&buff.prod); 
    } 

    pthread_exit(NULL); 
} // end thread: producer 


void *consumer1(void *dummy) 
{ 
    (void)dummy; 

    //signal(SIGUSR1, handler1); 
    printf("waiting 1\n"); 

    while(1) 
    { 
     sem_wait(&buff.con1); 
     // do something 
     //sem_post(&buff.prod); 
    } 

    pthread_exit(NULL); 
} // end thread: consumer1 


void *consumer2(void *dummy) 
{ 
    (void)dummy; 

    //signal(SIGUSR2, handler2); 
    printf("waiting 2\n"); 

    while(1) 
    { 
     sem_wait(&buff.con2); 
     // do something 
     //sem_post(&buff.prod); 
    } 

    pthread_exit(NULL); 
} // end thread: consumer2 


void handler(int signum) 
{ 
    sem_post(&buff.prod); 
    if(signum==SIGUSR1) 
    { 
     //sem_wait(&buff.con); 
     puts("Caught 1"); 
     buff.received++; 
     buff.SIG1++; 

     sem_post(&buff.con1); 
    } 

    else if(signum==SIGUSR2) 
    { 
     //sem_wait(&buff.con); 
     puts("caught 2"); 
     buff.received++; 
     buff.SIG2++; 

     sem_post(&buff.con2); 
    } 
} // end signal handler: handler2 


int main(void) 
{ 
    pthread_t threads[ MAX_THREADS ]; 
    buff.SIG1=0; 
    buff.SIG2=0; 
    buff.sent=0; 
    buff.received=0; 
    int index; 


    sem_init(&buff.con1, 0, 0); 
    sem_init(&buff.con2, 0, 0); 
    sem_init(&buff.prod, 0, 0); 

    signal(SIGUSR2, handler); 
    signal(SIGUSR1, handler); 

    for (index = 0; index < NP; index++) 
    { 
     pthread_create(&threads[index], NULL, producer,NULL); 
    } 

    for (index = 0;index < NC1;index++) 
    { 
     pthread_create(&threads[index+4], NULL, consumer1,NULL); 
    } 

    for (index = 0;index < NC2;index++) 
    { 
     pthread_create(&threads[index+6], NULL, consumer2,NULL); 
    } 

    for(size_t x=0; x<MAX_THREADS; x++) 
    { 
     pthread_join(threads[x], NULL); 
    } 
} // end function: main 

Тем не менее, методы обработки сигналов для потоков не использует kill() как для процессов.

, а код должен использовать функции, аналогичные ::

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); 
int pthread_cond_signal(pthread_cond_t *cond) 

сигнальной нить должна блокировать на pthread_cond_wait() вызова, пока другой поток не посылает сигнал, используя pthread_cond_signal(), с одной и тем же переменным состоянием.

Учитывая аналогию с сигналами, передаваемыми процессам, это немного отличается, поскольку сигнальный поток уже приостановил выполнение, ожидая сигнала, в отличие от процесса, который просто прерывается и продолжается.

+0

Я пытался с добавлением wait() в конце main и с циклом, определенным как while (1) {}, но затем потоки останавливаются после одного сигнала, а GDB дает мне это в конце. Сигнал приема программы SIGUSR1, определенный сигнал пользователя 1. [Переключение на тему 0x7ffff77f6700 (LWP 5666)] consumer1() в lab3.c: 62 \t} (GDB) продолжается. Пойманный 1 Caught 1 Caught 1 Поймали 1 [Новая тема 0x7ffff4ff1700 (LWP 5671)] [Новая тема 0x7ffff47f0700 (LWP 5672)] [Новая тема 0x7ffff3fef700 (LWP 5673)] –

+0

Ждание() функции для когда отдельный/дочерний процесс завершается, обычно, когда этот дочерний процесс был создан посредством вызова fork(), я отредактировал свой ответ с некоторыми предложениями об использовании 'pthread_join()' и 'pthread_exit()' и при использовании 'pthread_cond_wait () 'и' pthread_cond_signal() ' – user3629249

+0

Я вставил редактирование кода, использующего' phread_join() 'и' pthread_exit() 'Что случилось с этим EDIT? – user3629249

Смежные вопросы