생산자 소비자 문제

EEEFFEE·2024년 1월 11일
0

임베디드 리눅스

목록 보기
14/14

24.01.12 최초 작성

consumer, producer

  • consumer() : 파일을 열어 내용을 읽어 출력

void *consumer(void *arg)
{
	int fd, i;
	struct readout rbuf;

	printf("Consumer Thread(%d) start\n", (int)arg);
	if ((fd = open("/dev/kdt_producer_consumer_driver", O_RDONLY)) < 0) {
		printf("Error while open /dev/kdt_producer_consumer_driver in thread %d\n", (int)arg); 
		return;
	}
	for (i = 0; i < loop_count; i++) {
		read(fd, &rbuf, sizeof(rbuf));
		if (rbuf.index != rbuf.value)
			printf("Thread id: [%d], index: [%d], value: [%d]\n", (int)arg, rbuf.index, rbuf.value);
	}
	close(fd);
	printf("Consumer Thread(%d) end\n", (int)arg);
}

  • producer() : 파일을 열어 내용을 쓰는 함수


void *producer(void *arg)
{
	int fd, i;

	printf("Producer Thread(%d) start\n", (int)arg);
	if ((fd = open("/dev/kdt_producer_consumer_driver", O_WRONLY)) < 0) {
		printf("Error while open /dev/kdt_producer_consumer_driver in thread %d\n", (int)arg); 
		return;
	}
	for (i = 0; i < loop_count * 3; i++) {
		write(fd, &i, sizeof(int));
	}
	close(fd);
	printf("Producer Thread(%d) end\n", (int)arg);
}

  • main() : consumer()스레드 3개, producer()스레드 1개 생성

int main(int argc, char *argv[])
{
	// 소비자 3개 스레드 시작
	for (i = 0; i < MAX_CON_THREAD; i++)
		pthread_create(thread + i, NULL, consumer, (void *)i);
	// 생산자 1개 스레드 시작
	pthread_create(thread + i, NULL, producer, (void *)i);
	for (i = 0; i < (MAX_CON_THREAD + 1); i++)
		pthread_join(thread[i], NULL);

error:	close(fd);
	return 0;
}

driver

  • kdt_driver_read() : bufferwrite마무리할 때 까지 busy waiting 상태로 기다리다 종료되면 읽음

static ssize_t kdt_driver_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
{
	struct readout kernel_buf;

	while (head == tail)
		;
	kernel_buf.index = read_count;
	read_count = read_count + 1;
	kernel_buf.value = buffer[tail];
	tail = (tail + 1) % MAX_BUF_ENTRY;
	copy_to_user(buf, &kernel_buf, count);

	return count;
}

  • kdt_driver_write() : user공간에서 입력한 내용 buffer에 저장하고 모두 읽을 때 까지 busy watiting상태로 기다림

ssize_t kdt_driver_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
{
	int kernel_buf;

	while (((head + 1) % MAX_BUF_ENTRY) == tail)
		;
	copy_from_user(&kernel_buf, buf, count);
	buffer[head] = kernel_buf;
	head = (head + 1) % MAX_BUF_ENTRY;

	return count;
}

driver 개선

  • kdt_driver_read() : wait_event_interruptible()을 통해 스레드를 sleep상태로 두고 특정 조건을 만족하면 깨움, spin_lock()을 통해 read_count, kernel_buf, tail에 동시에 조작되는 것을 방지

#include <linux/wait.h>

DECLARE_WAIT_QUEUE_HEAD(full_wait);
DECLARE_WAIT_QUEUE_HEAD(empty_wait);

spinlock_t procon_lock;

static int __init kdt_module_init(void)
{
	...
    
    init_waitqueue_head(&full_wait);
	init_waitqueue_head(&empty_wait);
	spin_lock_init(&procon_lock);
    
    ...

}

static ssize_t kdt_driver_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
{
	struct readout kernel_buf;

	wait_event_interruptible(empty_wait, head != tail);
	spin_lock(&procon_lock);
	
	kernel_buf.index = read_count;
	read_count = read_count + 1;
	kernel_buf.value = buffer[tail];
	pr_info("read buf[%d] : %d\n", tail, kernel_buf.value);
	tail = (tail + 1) % MAX_BUF_ENTRY;
	copy_to_user(buf, &kernel_buf, count);

	spin_unlock(&procon_lock);
	wake_up_interruptible(&full_wait);

	return count;
}

  • kdt_driver_write() : wait_event_interruptible()을 통해 sleep상태에서 조건을 충족하면 깨움

ssize_t kdt_driver_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
{
	int kernel_buf;

	wait_event_interruptible(full_wait, ((head + 1) % MAX_BUF_ENTRY) != tail);

	copy_from_user(&kernel_buf, buf, count);
	buffer[head] = kernel_buf;
	pr_info("write buf[%d] : %d\n", head, kernel_buf);
	head = (head + 1) % MAX_BUF_ENTRY;

	wake_up_interruptible(&empty_wait);

	return count;
}

0개의 댓글

관련 채용 정보