24.01.12 최초 작성
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;
}
kdt_driver_read()
: buffer
에 write
마무리할 때 까지 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;
}
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;
}