I am implementing a lockfree linked list in C, similar to what's available in linux kernel llist.h. I am using atomic operation of "__sync_bool_compare_and_swap".
Here is the code snipet:
struct llist_head {
struct llist_node *head;
struct llist_node *tail;
};
struct llist_node {
struct llist_node *next;
int mm_ref;
};
#define LLIST_HEAD_INIT(name) { NULL, NULL }
#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name)
void llist_insert_tail(struct llist_head *head, struct llist_node *new)
{
volatile struct llist_node *last;
new->mm_ref = 0;
mb();
new->next = NULL;
do {
last = head->tail;
if (last)
last->next = new;
} while(!CAS(&(head->tail), last, new));
CAS(&(head->head), NULL, new);
mb();
}
struct llist_node *llist_remove_head(struct llist_head *head)
{
volatile struct llist_node *first, *next;
do {
first = head->head;
if (first != head->head)
continue;
if (first == NULL)
return 0;
next = first->next;
printf("%s: tid=%lx first=%p next=%p first->next=%p\n",
__func__, pthread_self(), first, next, first->next);
} while(!CAS(&(head->head), first, next));
return first;
}
I have a small multi-thread test program, there is only 1 producer thread to insert node into the tail list, and two consumers threads to remove the node from head of the list. The insert/remove functions are showed bellow:
void *list_insert(void *data)
{
int i;
printf("producer: id=%lx\n", pthread_self());
for ( i = 0 ; i < 10 ; i++) {
struct my_list_node *e = malloc(sizeof(struct my_list_node));
e->a = SOMEID;
llist_insert_tail(&global_list, &(e_array[i]->list));
printf("new node p=%p next=%p\n", e_array[i], e_array[i]->list.next);
ATOMIC_ADD64(&cn_added, 1);
}
ATOMIC_SUB(&cn_producer, 1);
printf("Producer thread [%lx] exited! Still %d running...\n",pthread_self(), cn_producer);
return 0;
}
void *list_remove(void *data)
{
struct llist_node *pos = NULL;
printf("consumer: id=%lx\n", pthread_self());
while(cn_producer || !llist_empty(&global_list)) {
struct my_list_node *e;
pos = llist_remove_head(&global_list);
if (pos) {
e = llist_entry(pos, struct my_list_node, list);
printf("tid=%lx removed %p\n", pthread_self(), pos);
if (e->a != SOMEID) {
printf("data wrong!!\n");
exit(1);
}
ATOMIC_ADD64(&cn_deleted, 1);
} else {
sched_yield();
}
}
printf("Consumer thread [%lx] exited %d\n", pthread_self(), cn_producer);
return 0;
}
The test showing consistent failure, e.g. the producer inserted 10 nodes,but the consumer only popped 1/2 or 3 nodes, one of the typical output i got showed bellow:
consumer: id=7f4d469e8700
consumer: id=7f4d461e7700
producer: id=7f4d459e6700
new node p=0x7f4d400008c0 next=(nil)
new node p=0x7f4d400008e0 next=(nil)
new node p=0x7f4d40000900 next=(nil)
new node p=0x7f4d40000920 next=(nil)
new node p=0x7f4d40000940 next=(nil)
new node p=0x7f4d40000960 next=(nil)
new node p=0x7f4d40000980 next=(nil)
new node p=0x7f4d400009a0 next=(nil)
new node p=0x7f4d400009c0 next=(nil)
new node p=0x7f4d400009e0 next=(nil)
Producer thread [7f4d459e6700] exited! Still 0 running...
llist_remove_head: tid=7f4d469e8700 first=0x7f4d400008c0 next=(nil) first->next=(nil)
llist_remove_head: tid=7f4d469e8700 head=(nil)
tid=7f4d469e8700 removed 0x7f4d400008c0
Consumer thread [7f4d469e8700] exited 0
llist_remove_head: tid=7f4d461e7700 first=0x7f4d400008c0 next=(nil) first->next=(nil)
Consumer thread [7f4d461e7700] exited 0
As can be seen, the producer threads exited first,and switched to consumer threads, however, this line:
llist_remove_head: tid=7f4d469e8700 first=0x7f4d400008c0 next=(nil) first->next=(nil)
showing that one of the consumer thread is trying to remove first node, but it's next pointer points to the NULL, which should NOT be the case since by now, the list is fully populated (with 10 nodes).
So there are race condition, which suppose to happen since this is lock-free list, but I scratch my head and couldn't figure out what kind of race condition could cause this output.
This implementation is similar to https://github.com/darkautism/lfqueue
But I can't figure out why my version doesn't work.
You may try lfqueue
It is simple to use, it is circular design lock free
int *ret;
lfqueue_t results;
lfqueue_init(&results);
/** Wrap This scope in multithread testing **/
int_data = (int*) malloc(sizeof(int));
assert(int_data != NULL);
*int_data = i++;
/*Enqueue*/
while (lfqueue_enq(&results, int_data) != 1) ;
/*Dequeue*/
while ( (ret = lfqueue_deq(&results)) == NULL);
// printf("%d\n", *(int*) ret );
free(ret);
/** End **/
lfqueue_clear(&results);
There is a lfstack which come together with same developer.
Related
I tried using malloc on this table - struct that contains rows that contain cells. First I allocate the table, then succesfully add and initialize first row, but when trying to set cell count on second row it crashes - I have no idea why, probably some leftover from previous pointer? Or do I need to allocate memory even for props of the structs? This is my first time digging into malloc, so sorry if it is something trivial.
typedef struct cell_t
{
char* content;
int contentLength;
} cell_t;
typedef struct row_t
{
cell_t* cells[100];
int cellCount;
} row_t;
typedef struct table_t
{
row_t* rows[100];
int rowCount;
} table_t;
row_t* allocateRow()
{
row_t* allocatedRow;
allocatedRow = malloc(sizeof(row_t*));
if (allocatedRow)
{
printf("THIS PRINTS TWICE");
allocatedRow->cellCount = 0;
printf("THIS PRINTS ONCE");
}
else
{
printf("FAILED TO ALLOCATE ROW!");
}
return allocatedRow;
}
void addRow(table_t* tableToAddTo, int nToAllocate)
{
while (tableToAddTo->rowCount < nToAllocate)
{
tableToAddTo->rows[tableToAddTo->rowCount] = allocateRow();
tableToAddTo->rowCount++;
}
}
int main()
{
table_t* inputTable = malloc(sizeof(table_t));
if (inputTable)
{
inputTable->rowCount = 0;
}
else
{
printf("FAILED TO ALLOCATE TABLE!");
return 1;
}
addRow(inputTable, 5);
for (int i = 0; i < inputTable->rowCount; i++)
{
free(inputTable->rows[i]);
}
free(inputTable);
return 0;
}
In allocateRow() change
allocatedRow = malloc(sizeof(row_t*));
into
allocatedRow = malloc(sizeof(row_t));
And you will need to allocate cells or change
cell_t* cells[100];
into
cell_t cells[100];
I am trying to implement a simple producer/consumer code using pthreads. The only common shared data between producer and consumer thread is the count variable used for counting the number of available elements in the shared array. What is happening is the count updated in one thread is not getting reflected in other. How can I make sure the writes to count in one thread appear in other as well? Am I missing something?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define ARRAY_SIZE 100
int array[ARRAY_SIZE];
volatile int count;
int head;
int tail;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *producer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == ARRAY_SIZE) {
printf("\nNo space for new items waiting for consumer to consume");
pthread_cond_wait(&empty, &mutex);
// Sometimes, why is count variable still ARRAY_SIZE.
// How do I make sure writes to 'count' variable in
// consumer thread is visible immediately in producer
// thread?
if (count == ARRAY_SIZE) {
printf("\ncount is still ARRAY_SIZE");
exit(0);
}
}
head %= ARRAY_SIZE;
count++;
array[head] = head;
printf("\nproduced %d/%d", head, count);
head++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&full);
}
}
void *consumer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == 0) {
printf("\nNo items available waiting for producer to produce");
pthread_cond_wait(&full, &mutex);
// Sometimes, why is count variable still zero. How do I
// make sure writes to 'count' variable in producer
// thread is visible immediately in consumer thread?
if (count == 0) {
printf("\ncount is still zero");
exit(0);
}
}
tail %= ARRAY_SIZE;
int ele = array[tail];
count--;
printf("\nconsumed %d/%d", tail, count);
tail++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&empty);
}
}
int main()
{
pthread_t producer_thread;
pthread_t consumer_thread;
int ret = 0;
setbuf(stdout, NULL);
ret = pthread_create(&producer_thread, NULL, producer, NULL);
if (ret != 0) {
printf("\nUnable to create producer thread %d", ret);
goto exit;
}
ret = pthread_create(&consumer_thread, NULL, consumer, NULL);
if (ret != 0) {
printf("\nUnable to create consumer thread %d", ret);
goto exit;
}
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
exit:
return ret;
}
produced 72/99
produced 73/100
No space for new items waiting for consumer to consume
consumed 74/99
consumed 75/98
consumed 76/97
consumed 77/96
produced 74/97
produced 75/98
produced 76/99
produced 77/100
No space for new items waiting for consumer to consume
count is still ARRAY_SIZE <------ incorrect
consumed 21/2
consumed 22/1
consumed 23/0
No items available waiting for producer to produce
produced 24/1
consumed 24/0
No items available waiting for producer to produce
produced 25/1
produced 26/2
produced 27/3
consumed 25/2
consumed 26/1
consumed 27/0
No items available waiting for producer to produce
count is still zero <------ incorrect
Solution that worked after the fix from Zan Lynx
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define ARRAY_SIZE 100
int array[ARRAY_SIZE];
volatile int count;
int head;
int tail;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *producer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == ARRAY_SIZE) {
printf("\nNo space for new items waiting for consumer to consume");
// Spurious wakeups from the pthread_cond_timedwait() or
// pthread_cond_wait() functions may occur. Since the
// return from pthread_cond_timedwait() or
// pthread_cond_wait() does not imply anything about the
// value of this predicate, the predicate should be
// re-evaluated upon such return.
while (count == ARRAY_SIZE)
pthread_cond_wait(&empty, &mutex);
}
head %= ARRAY_SIZE;
count++;
array[head] = head;
printf("\nproduced %d/%d", head, count);
head++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&full);
}
return NULL;
}
void *consumer(void *args)
{
int res = 0;
while (1) {
pthread_mutex_lock(&mutex);
if (count == 0) {
printf("\nNo items available waiting for producer to produce");
// Spurious wakeups from the pthread_cond_timedwait() or
// pthread_cond_wait() functions may occur. Since the
// return from pthread_cond_timedwait() or
// pthread_cond_wait() does not imply anything about the
// value of this predicate, the predicate should be
// re-evaluated upon such return.
while (count == 0)
pthread_cond_wait(&full, &mutex);
}
tail %= ARRAY_SIZE;
int ele = array[tail];
count--;
printf("\nconsumed %d/%d", tail, count);
tail++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&empty);
}
return NULL;
}
int main()
{
pthread_t producer_thread;
pthread_t consumer_thread;
int ret = 0;
setbuf(stdout, NULL);
ret = pthread_create(&producer_thread, NULL, producer, NULL);
if (ret != 0) {
printf("\nUnable to create producer thread %d", ret);
goto exit;
}
ret = pthread_create(&consumer_thread, NULL, consumer, NULL);
if (ret != 0) {
printf("\nUnable to create consumer thread %d", ret);
goto exit;
}
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
exit:
return ret;
}
I believe you missed the fact that condition waits must always check the predicate again after the wait returns. There must be a loop.
The wait may end for all sorts of reasons besides a signal/notify call.
I am learning to write kernel modules and in one of the examples I had to make sure that a thread executed 10 times and exits, so I wrote this according to what I have studied:
#include <linux/module.h>
#include <linux/kthread.h>
struct task_struct *ts;
int flag = 0;
int id = 10;
int function(void *data) {
int n = *(int*)data;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(n*HZ); // after doing this it executed infinitely and i had to reboot
while(!kthread_should_stop()) {
printk(KERN_EMERG "Ding");
}
flag = 1;
return 0;
}
int init_module (void) {
ts = kthread_run(function, (void *)&id, "spawn");
return 0;
}
void cleanup_module(void) {
if (flag==1) { return; }
else { if (ts != NULL) kthread_stop(ts);
}
return;
}
MODULE_LICENSE("GPL");
What I want to know is :
a) How to make thread execute 10 times like a loop
b) How does the control flows in these kind of processes that is if we make it to execute 10 times then does it go back and forth between function and cleanup_module or init_module or what exactly happens?
If you control kthread with kthread_stop, the kthread shouldn't exit until be ing stopped (see also that answer). So, after executing all operations, kthread should wait until stopped.
Kernel already implements kthread_worker mechanism, when kthread just executes works, added to it.
DEFINE_KTHREAD_WORKER(worker);
struct my_work
{
struct kthread_work *work; // 'Base' class
int n;
};
void do_work(struct kthread_work *work)
{
struct my_work* w = container_of(work, struct my_work, work);
printk(KERN_EMERG "Ding %d", w->n);
// And free work struct at the end
kfree(w);
}
int init_module (void) {
int i;
for(i = 0; i < 10; i++)
{
struct my_work* w = kmalloc(sizeof(struct my_work), GFP_KERNEL);
init_kthread_work(&w->work, &do_work);
w->n = i + 1;
queue_kthread_work(&worker, &w->work);
}
ts = kthread_run(&kthread_worker_fn, &worker, "spawn");
return 0;
}
void cleanup_module(void) {
kthread_stop(ts);
}
I have an assignment to implement Producer consumer problem in a convoluted way(may be to test my understanding). The parent process should set up a shared memory. The unnamed semaphores(for empty count and filled count) should be initialized and a mutex should be initialized. Then two child processes are created, a producer child and a consumer child. Each child process should create a new thread which should do the job.
PS: I have read that the semaphore's should be kept in a shared memory as they would be shared by different processes.
Please provide some hints, or suggest changes.
So far, I have done this:
struct shmarea
{
unsigned short int read;
unsigned short int max_size;
char scratch[3][50];
unsigned short int write;
sem_t sem1;// Empty slot semaphore
sem_t sem2;// Filled slot Semaphore
};
void *thread_read(void* args);
void *thread_write(void *args);
pthread_mutex_t work_mutex;
struct shmarea *shma;
int main()
{
int fork_value,i=0,shmid;
printf("Parent process id is %d\n\n",getpid());
int res1,res2;
key_t key;
char *path = "/tmp";
int id = 'S';
key = ftok(path, id);
shmid = shmget(key,getpagesize(),IPC_CREAT|0666);
printf("Parent:Shared Memory id = %d\n",id);
shma = shmat(shmid,0,0);
shma->read = 0;
shma->max_size = 3;
shma->write = 0;
pthread_t a_thread;
pthread_t b_thread;
void *thread_result1,*thread_result2;
res1 = sem_init(&(shma->sem1),1,3);//Initializing empty slot sempahore
res2 = sem_init(&(shma->sem2),1,0);//Initializing filled slot sempahore
res1 = pthread_mutex_init(&work_mutex,NULL);
while(i<2)
{
fork_value = fork();
if(fork_value > 0)
{
i++;
}
if(fork_value == 0)
{
if(i==0)
{
printf("***0***\n");
//sem_t sem1temp = shma->sem1;
char ch;int res;
res= pthread_create(&a_thread,NULL,thread_write,NULL);
}
if(i==1)
{
printf("***1***\n");
//sem_t sem2temp = shma->sem2;
int res;
char ch;
res= pthread_create(&b_thread,NULL,thread_read,NULL);
}
}
}
int wait_V,status;
res1 = pthread_join(a_thread,&thread_result1);
res2 = pthread_join(b_thread,&thread_result2);
}
void *thread_read(void *args)
{
while(1)
{
sem_wait(&(shma->sem2));
pthread_mutex_lock(&work_mutex);
printf("The buf read from consumer:%s\n",shma->scratch[shma->read]);
shma->read = (shma->read+1)%shma->max_size;
pthread_mutex_unlock(&work_mutex);
sem_post(&(shma->sem1));
}
}
void *thread_write(void *args)
{
char buf[50];
while(1)
{
sem_wait(&(shma->sem1));
pthread_mutex_lock(&work_mutex);
read(STDIN_FILENO,buf,sizeof(buf));
strcpy(shma->scratch[shma->write],buf);
shma->write = (shma->write+1)%shma->max_size;
pthread_mutex_unlock(&work_mutex);
sem_post(&(shma->sem2));
}
}
(1) Your biggest problem by far is that you have managed to write a fork bomb. Because you don't exit either child in the fork loop each child is going to fall through and loop around and create their own children until you crash or bring the system down. You want something more like this:
while(i < 2)
{
fork_value = fork();
if(fork_value > 0)
i++;
if(fork_value == 0)
{
if(i==0)
{
printf("0 child is pid %d\n", getpid());
int res;
res = pthread_create(&a_thread,NULL,thread_write,NULL);
res = pthread_join(a_thread,&thread_result1);
exit(0);
}
if(i==1)
{
printf("1 child is pid %d\n", getpid());
int res;
res = pthread_create(&b_thread,NULL,thread_read,NULL);
res = pthread_join(b_thread,&thread_result2);
exit(0);
}
}
}
for (i = 0; i < 2; ++i)
wait(NULL);
Notice the wait on the children which you neglected.
(2) Always check your return codes. They are like safety belts, a bit of a drag but so helpful when you crash. (Yes, I didn't take my advice here but you should.)
(3) These names are awful.
unsigned short int read;
unsigned short int write;
Stay away from naming variables after system calls. It's confusing and just asking for trouble.
(4) Terminology wise, processes with a common ancestor, like these, are related. The parent can open shared memory and other resources and pass it on to the children. Unrelated processes would, for example, multiple instances of program launched from different terminals. They can share resources but not in the "inherited" way forked processes do.
It's late and didn't get around to looking at what you are doing with the threads and such but this should get you started.
I need to implement producer-consumer problem in my project. N consumers and M producers will be created. A producer will use publish(v) call to reach v data to consumer. A consumer will use get_data(v) call to get a copy of data v. I really don't know how to implement it. Please help me.
I am going to use C to implement it. I will create n process for consumers and m process for producers. If a producer publish a data, other producers can not do it until all consumers get it. I will use semaphores and shared memory to exchange data.
I found something which does similar job. But it is using threads but i need process instead. How can i change this.
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define BUFF_SIZE 4
#define FULL 0
#define EMPTY 0
char buffer[BUFF_SIZE];
int nextIn = 0;
int nextOut = 0;
sem_t empty_sem_mutex; //producer semaphore
sem_t full_sem_mutex; //consumer semaphore
void Put(char item)
{
int value;
sem_wait(&empty_sem_mutex); //get the mutex to fill the buffer
buffer[nextIn] = item;
nextIn = (nextIn + 1) % BUFF_SIZE;
printf("Producing %c ...nextIn %d..Ascii=%d\n",item,nextIn,item);
if(nextIn==FULL)
{
sem_post(&full_sem_mutex);
sleep(1);
}
sem_post(&empty_sem_mutex);
}
void * Producer()
{
int i;
for(i = 0; i < 10; i++)
{
Put((char)('A'+ i % 26));
}
}
void Get()
{
int item;
sem_wait(&full_sem_mutex); // gain the mutex to consume from buffer
item = buffer[nextOut];
nextOut = (nextOut + 1) % BUFF_SIZE;
printf("\t...Consuming %c ...nextOut %d..Ascii=%d\n",item,nextOut,item);
if(nextOut==EMPTY) //its empty
{
sleep(1);
}
sem_post(&full_sem_mutex);
}
void * Consumer()
{
int i;
for(i = 0; i < 10; i++)
{
Get();
}
}
int main()
{
pthread_t ptid,ctid;
//initialize the semaphores
sem_init(&empty_sem_mutex,0,1);
sem_init(&full_sem_mutex,0,0);
//creating producer and consumer threads
if(pthread_create(&ptid, NULL,Producer, NULL))
{
printf("\n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&ctid, NULL,Consumer, NULL))
{
printf("\n ERROR creating thread 2");
exit(1);
}
if(pthread_join(ptid, NULL)) /* wait for the producer to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if(pthread_join(ctid, NULL)) /* wait for consumer to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
sem_destroy(&empty_sem_mutex);
sem_destroy(&full_sem_mutex);
//exit the main thread
pthread_exit(NULL);
return 1;
}
I'd suggest you to make a plan and start reading. For example:
Read about how to create and manage threads. Hint: pthread.
Think how will the threads communicate - usually they use common data structure. Hint: message queue
Think how to protect the data structure, so both threads can read and write safely. Hint: mutexes.
Implement consumer and producer code.
Really, if you want more information you have to work a bit and ask more specific questions. Good luck!