Я пытаюсь реализовать проблему производителя-потребителя, используя сценарий с двумя процессами.
Процесс1 — Производитель, а Процесс2 — Потребитель. Процесс-потребитель ожидает переменной условия (pthread_cond_wait(cond)
), и производитель отправит сигнал потребителю через pthread_cond_signal(cond)
.
Я прошел по этим ссылкам общий мьютекс и переменная условия в процессе pthread_mutexattr_setpshared
</ a> везде было сказано, что можно использовать мьютекс и условную переменную в нескольких процессах,
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
В этой ссылке
общие мьютексы В качестве рекомендации void было сказано проверить, поддерживает ли моя система или нет? Я проверил и получил 200809 в качестве возвращаемого значения sysconf(_SC_THREAD_PROCESS_SHARED)
, что означает, что моя система поддерживает PTHREAD_PROCESS_SHARED
.
Я пытаюсь отправить pthread_cond_signal
от производителя (процесс-1) потребителю (процесс-2). И производитель, и потребитель используют одну и ту же инициализированную переменную мьютекса/условия.
Однако потребитель не получает сигнал. Похоже, либо сигнал не отправляется, либо он потерян.
Где я делаю ошибки? Я использую Ubuntu, gcc-4.6.3.
Вот мой код.
Производитель.с:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sched.h>
#include <syscall.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdbool.h>
pthread_cond_t* condition;
pthread_mutex_t* mutex;
#define OKTOWRITE "/oktowrite"
#define MESSAGE "/message"
#define MUTEX "/lock"
struct shared_use_st
{
bool conditionSatisfied;
};
struct shared_use_st *shared_stuff;
void create_shared_memory()
{
int shmid;
void *shared_memory=(void *)0;
shmid =shmget( (key_t)1234, 4096, 0666 | IPC_CREAT );
if (shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
shared_memory =shmat(shmid, (void *)0,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
shared_stuff = (struct shared_use_st *)shared_memory;
}
int main()
{
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0) {
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mutex == MAP_FAILED ) {
perror("Error on mmap on mutex\n");
exit(1);
}
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0) {
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (condition == MAP_FAILED ) {
perror("Error on mmap on condition\n");
exit(1);
}
/* set mutex shared between processes */
pthread_mutexattr_t mutexAttr;
pthread_mutexattr_init(&mutexAttr);
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexAttr);
/* set condition shared between processes */
pthread_condattr_t condAttr;
pthread_condattr_init(&condAttr);
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(condition, &condAttr);
create_shared_memory();
shared_stuff->conditionSatisfied=0;
int count=0;
while(count++<10)
{
pthread_mutex_lock(mutex);
shared_stuff->conditionSatisfied=1;
pthread_mutex_unlock(mutex);
pthread_cond_signal(condition);
printf("signal sent to consumer, %d\n",count);
sleep(3);
}
pthread_condattr_destroy(&condAttr);
pthread_mutexattr_destroy(&mutexAttr);
pthread_mutex_destroy(mutex);
pthread_cond_destroy(condition);
shm_unlink(OKTOWRITE);
shm_unlink(MESSAGE);
shm_unlink(MUTEX);
return 0;
}
Потребитель.c:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sched.h>
#include <syscall.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdbool.h>
pthread_cond_t* condition;
pthread_mutex_t* mutex;
#define OKTOWRITE "/oktowrite"
#define MESSAGE "/message"
#define MUTEX "/lock"
struct shared_use_st
{
bool conditionSatisfied;
};
struct shared_use_st *shared_stuff;
void create_shared_memory()
{
int shmid;
void *shared_memory=(void *)0;
shmid =shmget( (key_t)1234, 4096, 0666 | IPC_CREAT );
if (shmid == -1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
shared_memory =shmat(shmid, (void *)0,0);
if(shared_memory == (void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
shared_stuff = (struct shared_use_st *)shared_memory;
}
int main()
{
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0) {
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mutex == MAP_FAILED ) {
perror("Error on mmap on mutex\n");
exit(1);
}
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0) {
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (condition == MAP_FAILED ) {
perror("Error on mmap on condition\n");
exit(1);
}
/* set mutex shared between processes */
pthread_mutexattr_t mutexAttr;
pthread_mutexattr_init(&mutexAttr);
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexAttr);
/* set condition shared between processes */
pthread_condattr_t condAttr;
pthread_condattr_init(&condAttr);
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(condition, &condAttr);
create_shared_memory();
shared_stuff->conditionSatisfied=0;
while(1)
{
printf("Receiver waits on for signal from hello1.c \n");
pthread_mutex_lock(mutex);
while(!shared_stuff->conditionSatisfied)
pthread_cond_wait(condition, mutex);
pthread_mutex_unlock(mutex);
printf("Signal received, wake up!!!!!!!!\n");
//reset
pthread_mutex_lock(mutex);
shared_stuff->conditionSatisfied=0;
pthread_mutex_unlock(mutex);
}
}
Мне кажется, что вы неправильно используете разделяемую память: вы вызываете в обоих процессах shm_open с O_CREATE, а также ftruncate. Только один процесс должен создать сегмент разделяемой памяти и изменить его размер. Другой должен прикрепиться к нему. — person bholanath schedule 18.01.2016
Вы пытались поделиться чем-то между двумя процессами, прежде чем работать с мьютексом? — person bholanath schedule 18.01.2016
@terencehill, AFIK, другой процесс сначала проверит, существует ли уже общая память или нет. Если он уже есть, он не создаст новый, а только присоединится к существующему. — person bholanath schedule 18.01.2016
@terencehill, проблема в том, что обновленное значение conditionSatisfied не отображается в потребительском процессе. — person bholanath schedule 18.01.2016
В каком порядке происходят события? Вы усекаете как производителя, так и потребителя. — person bholanath schedule 18.01.2016
Более того, вы смешиваете старый shmget/shmat с sum_open, что меня немного сбивает с толку. — person bholanath schedule 18.01.2016
проблема заключается в том, что обновленное значение conditionSatisfied не отображается в процессе потребителя. Посмотрите на сгенерированные инструкции и убедитесь, что проверка не была оптимизирована. Вы также можете добавить некоторый код для отправки чего-либо в stderr
в цикле потребителя while
, чтобы убедиться, что потребитель получает сигнал. — person bholanath schedule 18.01.2016
@terencehill Кроме того, сигнал также не отправляется потребителю. Если я удалю предикат, то while(!shared_stuff-›conditionSatisfied) все равно потребитель не проснется. — person bholanath schedule 18.01.2016
@AndrewHenle Я тебя не понял. Я уже использовал gcc -O0 для отключения всей оптимизации. — person bholanath schedule 18.01.2016
@terencehill, сначала я запускаю потребителя, поэтому он ждет сигнала от производителя, затем я запускаю производителя. — person bholanath schedule 18.01.2016
Итак, усечение в производителе бессмысленно, но не должно быть проблемой. — person bholanath schedule 18.01.2016
Мьютекс, совместно используемый процессами, должен быть инициализирован только одним из них
Ошибка заключается в том, что вы инициализируете мьютекс и условие в обоих процессах. Однако, поскольку они являются общими, их следует инициализировать только на потребителе.
Я также предлагаю не смешивать старые функции System V shmget/shmat с новыми shm_open POSIX.
Я определил новое общее целое число shint, которое указывает на общую память, инициализированную с помощью shm_open и присоединенную через mmap. shint используется как флаг для ожидания условия pthread.
На мой взгляд, производитель, который запускается после потребителя, не нуждается в усечении сегмента памяти и может открыть общую память только с O_RDWR. Сначала производитель берет блокировку и устанавливает shint в 1.
С другой стороны, потребитель, который запускается первым, должен создать сегменты общей памяти и изменить их размер с помощью ftruncate. Он также устанавливает общий флаг shint в 0 и ожидает его. Кроме того, перед вызовом shm_open лучше развязать (через shm_unlik) все используемые сегменты общей памяти, чтобы убрать возможные ошибки при предыдущих вызовах (например, если перед развязкой произошел сбой кода).
Я перенес инициализацию атрибутов мьютекса и условия в начало, потому что это кажется более понятным и правильным.
Producer.c
Потребитель.c
спасибо, он отлично работает для отправки сигнала от производителя к потребителю. Я хочу отправлять данные от производителя к потребителю, поэтому я использовал общую память. Что вы предлагаете для отправки данных? Должен ли я просто создать общую память, используя shm_open, только что вы сделали shint int memory? — person bholanath; 18.01.2016
Это зависит от того, чего вы пытаетесь достичь. Лично я бы остановился на разделяемой памяти: вы можете реализовать почти все типы коммуникаций, просто используя правильные механизмы синхронизации и расположение данных в разделяемой памяти. — person bholanath; 18.01.2016