C linux sem_wait doesn't work (sometimes) in threads - c

I paste only model, which shows the problem. In function:
int get_random_prime(mpz_t number) I've got: sem_wait(&prime_count); and it doesn't work properrly.It waits and waits and waits even if semaphore is greater that 0.
#include<gmp.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
size_t number_of_cores=2;
pthread_mutex_t mutex_queue;
sem_t prime_count;
sem_t threads_count;
size_t last_length=0;
size_t prime_got=0;
char manager_on=0;
mpz_t prime;
get_random_odd(mpz_t output,size_t length){
size_t i;
size_t dev_random;
int randomFile= open("/dev/urandom", O_RDONLY);
read(randomFile,&dev_random,8);
mpz_set_ui(output,dev_random);
for(i=1;i<(length/64);i++){
read(randomFile,&dev_random,8);
mpz_mul_2exp (output,output, 64);
mpz_add_ui(output,output,dev_random);
}
close(randomFile);
mpz_setbit(output,length-1);
mpz_setbit(output,0);
}
void* get_random_prime_thread(void* ptr_length){
size_t result = 0;
size_t i;
size_t length = *((size_t*)ptr_length);
mpz_t number;
mpz_init(number);
//do{
get_random_odd(number, length);
i=0;
/* do{
result=miller_rabin_test(number);
i++;
}while(result==1 && i<prime_precision);*/
//}while(result==0);
pthread_mutex_lock(&mutex_queue);
mpz_set(prime,number);
pthread_mutex_unlock(&mutex_queue);
sem_post(&prime_count);
mpz_clear(number);
pthread_exit(NULL);
};
void* get_random_prime_manager_start(void* length){
size_t i;
size_t size=32;
pthread_t *threads=malloc(sizeof(pthread_t)*size);
manager_on =1;
pthread_t rc;
pthread_mutex_init(&mutex_queue,NULL);
sem_init(&threads_count,0,number_of_cores);
sem_init(&prime_count,0,0);
i=-1;
do{
sem_wait(&threads_count);
i++;
printf("PROCES:%d\n",i);
if(i>=size){
threads=realloc(threads,size*2);
}
rc=pthread_create(&threads[i],NULL,get_random_prime_thread,length);
if(rc){
printf("%s\n",strerror(errno));
pthread_exit((void*)-1);
}
}while(manager_on);
for(i;i>0;i--){
pthread_cancel(threads[i]);
}
free(threads);
pthread_mutex_destroy(&mutex_queue);
sem_destroy(&threads_count);
sem_destroy(&prime_count);
pthread_exit(NULL);
}
void* get_random_prime_manager_stop(){
manager_on=0;
}
int get_random_prime(mpz_t number){
sem_wait(&prime_count);
printf("GET\n");
pthread_mutex_lock(&mutex_queue);
mpz_set(number,prime);
pthread_mutex_unlock(&mutex_queue);
sem_post(&threads_count);
return 0;
};
int main(){
mpz_init(prime);
size_t rc;
size_t length=1024;
pthread_t thread;
mpz_t p,q,n;
mpz_init(p);
mpz_init(q);
mpz_init(n);
size_t half_length=length/2;
rc=pthread_create(&thread,NULL,get_random_prime_manager_start,(void*)&half_length);
if(rc){
printf("%s\n",strerror(errno));
return -1;
}
do{
get_random_prime(p);
get_random_prime(q);
mpz_mul(n,p,q);
}while( mpz_sizeinbase(n,2)==length);
get_random_prime_manager_stop();
mpz_clear(p);
mpz_clear(q);
mpz_clear(n);
}
Is it possible that thread wait on semaphore that hasn't been initiated yet?

You need to make sure the sem_init calls complete before you try to use any of the semaphores. The best way to do this is to call get_random_prime_manager_start normally and let it initialize the semaphores, start a thread, and then return. That way, you are assured that the manager is sufficiently started for it to be safe to use it when the function returns.

Related

Why is printf blocked by while(trylock) on CentOS 7?

Start two threads with policy SCHED_RR and priority 45.
One thread's affinity is 0x0004, and another is 0x0008.(my computer contains four cpu cores. system is CentOS 7, not a virtual machine.)
The subTask is simple:
spinning trylock in the while.
call printf show the information.
free the lock.
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#define CHECK_ERROR(call)\
do{\
int _error = (call);\
if(_error != 0){\
printf("*** Error *** at [%s:%d] error=%d \n", __FILE__, __LINE__, _error);\
}\
}while(0)
int getThreadCores(pthread_t thread, int *cores);
int getThreadPP(pthread_t thread, int *policy, int *priority);
int setThreadAttrCores(pthread_attr_t *attr, int cores);
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority);
#define SUB_THREAD_NUM (2)
static int threadsId[SUB_THREAD_NUM];
static pthread_t subThreads[SUB_THREAD_NUM];
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *subTask(void *data)
{
int id = *(int*)data;
int policy=0, priority=0, cores=0;
CHECK_ERROR(getThreadCores(pthread_self(), &cores));
CHECK_ERROR(getThreadPP(pthread_self(), &policy, &priority));
printf("the sub thread %d, cores 0x%x, policy %d, priority %d\n",
id,cores,policy,priority);
int n = 1024*10;
int i;
for(i=0;i<n;++i)
{
while(pthread_mutex_trylock(&lock)){}
printf("the sub thread %d, out put %d\n",id,i);
CHECK_ERROR(pthread_mutex_unlock(&lock));
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_attr_t attr;
CHECK_ERROR(pthread_attr_init(&attr));
int i;
for(i=0;i<SUB_THREAD_NUM;++i)
{
threadsId[i] = i;
CHECK_ERROR(setThreadAttrCores(&attr, 0x0004<<i));
CHECK_ERROR(setThreadAttrPP(&attr, SCHED_RR, 1));
CHECK_ERROR(pthread_create(&subThreads[i],&attr,subTask,threadsId+i));
}
CHECK_ERROR(pthread_attr_destroy(&attr));
for(i=0;i<SUB_THREAD_NUM;++i)
{
CHECK_ERROR(pthread_join(subThreads[i],NULL));
}
printf("multiThreadTest success\n");
return 0;
}
int getThreadCores(pthread_t thread, int *cores)
{
int error = 0;
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
int _cores = 0;
cpu_set_t mask;
CPU_ZERO(&mask);
error = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &mask);
if(error == 0)
{
int i;
for(i=0;i<cpuNum;++i)
{
if(CPU_ISSET(i, &mask))
{
_cores |= (0x1 << i);
}
}
}
*cores = _cores;
return error;
}
int getThreadPP(pthread_t thread, int *policy, int *priority)
{
int error = 0;
struct sched_param sp;
error = pthread_getschedparam(thread,policy,&sp);
*priority = sp.sched_priority;
return error;
}
static void setCpuSetMask(cpu_set_t *mask, int cores)
{
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
CPU_ZERO(mask);
int i;
for(i=0;i<cpuNum;++i)
{
if(((cores>>i)&0x1) == 1)
{
CPU_SET(i, mask);
}
}
}
int setThreadAttrCores(pthread_attr_t *attr, int cores)
{
cpu_set_t mask;
if(cores<0)cores=0xFFFFFFFF;
setCpuSetMask(&mask,cores);
return pthread_attr_setaffinity_np(attr, sizeof(cpu_set_t), &mask);
}
int setThreadAttrPriority(pthread_attr_t *attr, int priority)
{
struct sched_param sp;
sp.sched_priority = priority;
return pthread_attr_setschedparam(attr,&sp);
}
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority)
{
int error = 0;
//firstly, set the inherit to PTHREAD_EXPLICIT_SCHED
error |= pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED);
error |= pthread_attr_setschedpolicy(attr,policy);
error |= setThreadAttrPriority(attr,priority);
return error;
}
compile: gcc -Wall -O3 -lpthread multiThreadTest.c -o multiThreadTest
My question is: the program blocked, one thread blocked in printf and another blocked in spinning trylock, why?
If I change the policy to SCHED_OTHER and the priority to 0, the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to CHECK_ERROR(pthread_mutex_lock(&lock)); the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to while(pthread_mutex_trylock(&lock)){usleep(1);} the program unblocked.
And if I change the printf to fprintf, the program unblocked.
And if I run the same program on Ubuntu system, it is unblocked.

multi-threads and reading a file

I write a C code that reads a file and do some works on it, using multi-threads functions. I read file in the fun1 so I expect that file read linearly, but some tests I do on this code show me that it seems that the file does not read in the right order. What is wrong about my code?!
#include <pthread.h>
#define BUFSIZE 1024*10
#define NUM_THREADS 4
typedef struct _thread_data_t {
unsigned char id;
char *msg;
unsigned int msg_len;
} thread_data_t;
/* thread function */
void *thr_func(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
fun2(data->msg, data->msg_len);
pthread_exit(NULL);
}
void fun1(FILE *file) {
unsigned char i, j, buf[BUFSIZE];
pthread_t thr[NUM_THREADS];
thread_data_t thr_data[NUM_THREADS];
int rc, fr, fd = fileno(file);
for (;;) {
for (i = 0; i < NUM_THREADS; i++) {
fr = read(fd, buf, BUFSIZE);
if (fr <= 0) break;
thr_data[i].id = i;
thr_data[i].msg = buf;
thr_data[i].msg_len = fr;
if ((rc = pthread_create(&thr[i], NULL, thr_func, &thr_data[i]))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
fr = -1;
break;
}
}
for (j = 0; j < i; j++) {
pthread_join(thr[j], NULL);
}
if (fr <= 0) break;
}
}
Edit:
I think that until all threads finish their works nothing new read from the file. Is it true?
I think your problem is the single buffer:
buf[BUFSIZE];
In each loop you read data into that buffer and then prepare data for the thread
thr_data[i].msg = buf;
which I assume doesn't include a copy of the buffer itself. I assume msg is just a pointer.
So in the next iteration, you'll overwrite the buf with new data from the file and consequently change data for already created threads.
I guess you'll need
buf[NUM_THREADS][BUFSIZE];
so that each thread gets its own data area to work on.
Quote:
I think that until all threads finish their works nothing new read from the file. Is it true?
Correct, that's what pthread_join does for you

Asynchronous threads

I have two functions in C, that will be called by c++ threads (one thread per function). I want to block one, when the other is running and vice-versa. How can I solve this?
Here the resume:
int adin_mem_read(SP16 *buf, int sampnum, int client_id){
//(.....)
//lock writing_buffer
memcpy(&buf[real_size], stream_buffer_[client_id].data_ + stream_buffer_[client_id].p_read, stream_buffer_[client_id].p_write - stream_buffer_[client_id].p_read);
//unlock writing_buffer
//(....)
}
And:
int writing_bufer(struct Stream_Bufer * buffers, const char *data, int nbytes, int end_stream, int begin_stream) {
//(...)
//lock adin_mem_read()
memcpy(buffers->data_ + buffers->p_write, data, nbytes);
buffers->p_write += nbytes;
//(...)
//unlock adin_mem_read()
}

Fill file ASCII values

I want to create a file filled with 0 or other letters. Here's my function
int fill(const int d, struct aiocb *aiorp, void *buf, const int count){
int rv = 0;
memset( (void *)aiorp, 0, sizeof( struct aiocb ) ); // <-here second paramether is 0
aiorp->aio_fildes = d;
aiorp->aio_buf = buf;
aiorp->aio_nbytes = count;
aiorp->aio_offset = 0;
rv = aio_write( aiorp );
return rv;
}
Here's my main
int main(int argc, char * argv[]){
int des;
int rv;
struct aiocb aior;
char buffer[1000];
if(argc == 3){
printf("just %s\n", argv[1]);
des = createFile(argv[1]);
rv = fill(des, &aior, buffer, sizeof(buffer));
}
return 0;
}
So my output should be file filled with zero values, but my fle is filled with garbage
^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#$
y▒^X^#^#^#^#^#^#^#
s|▒^#^#^#^#^#^#^#^#^#^#^#^#▒r|▒^#^#^#^#▒▒^?▒(▒▒▒▒▒{▒▒
y▒^P^#^#^#▒
y▒^A^#^#^#d^Cy▒^#^#^#^#▒
y▒^T
y▒^P▒▒▒^#^#^#^#^#^#^#^
...
Why? What's wrong?
Here's the code :
sukurti - create new file if that file don't exist and
fill - fill created file
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <aio.h>
#define MB 1024
int sukurti(char *name);
int fill(const int d, struct aiocb *aiorp, void *buf, const int count);
int sukurti(char *name){
int dskr;
dskr = open( name, O_RDONLY );
if( dskr == -1 ){
printf("Failas sukurtas, nes jo nebuvo\n");
dskr = open( name, O_WRONLY | O_CREAT, 0644);
}else{
printf("Jau yra toks failas!\n");
exit(1);
}
return dskr;
}
int fill(const int d, struct aiocb *aiorp, void *buf, const int count){
int rv = 0;
memset( (void *)aiorp, 'A', sizeof( struct aiocb ) );
aiorp->aio_fildes = d;
aiorp->aio_buf = buf;
aiorp->aio_nbytes = count;
aiorp->aio_offset = 0;
rv = aio_write( aiorp );
return rv;
}
int main(int argc, char * argv[]){
int des;
int rv;
struct aiocb aior;
int x = atoi(argv[2]);
printf("%d\n", x);
int size = MB * MB * x;
char buffer[size];
if(argc == 3){
printf("just %s\n", argv[1]);
des = sukurti(argv[1]);
rv = fill(des, &aior, buffer, sizeof(buffer));
}else{
printf("Blogas\n");
}
return 0;
}
EDIT:
I know that my writting to file ends
Three ssues here:
buffer is not initalised. Do this using
memset(buffer,
<what ever 8bit value you want the file to be filled with>,
sizeof buffer);
right after defining it in main().
aior is initialise wrongly. Initialise it to all 0 using
memset(aiorb, 0, sizeof aior);
right after defining it in main() and remove the call to memset() in fill().
Finally the program most likely ends before the buffer had been asynchronously written to disk.
To fix this define a notification method as mentioned under man 7 aio. And make the program wait for this notification to be received before ending the program.
This for example can be done by asking for completion notification via signal and wait for this signal.
To do so modify your code as follows:
Add the following two lines to the intialisation of what aiorp is pointing to in fill():
aiorp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
aiorp->aio_sigevent.sigev_signo = SIGUSR1;
To be able to handle the notifying signal sent (without ending the program) a signal handler needs to be setup:
void handler(int sig)
{
/* Do nothing. */
}
Install this handler by calling
signal(handler, SIGUSR1);
right at the beginning of the program.
Before returning from main() call wait_for_completion(SIGUSR1) which might look like this:
void wait_for_completion(int sig)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, sig);
sigwait(&set, &sig); /* This blocks until sig had
been received by the program. */
printf("Completion notification for asynchronous 'write'-operation received.\n");
}
Add error handling as appropriate. I left it out for the sake of readability.
memset( (void *)aiorp, '0', sizeof( struct aiocb ) );
0 is not '0', you need to actually use the ASCII value (48 if i recall correctly.)

No thread seems to be executing

I am trying to solve the producer consumer problem using pthreads and semaphores. At the moment, neither of the threads seem to execute and even main isn't printing out a printf, it seems like the process is waiting for input. (so all that happens is, blinking cursor, then I press ctrl+c to end the process because nothing is happening). I have tested get_rand_num and that works. I am compiling with clang -Wall -std=c99 -lpthread -o randnumgen randnumgen.c
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
#include "sema.c"
typedef struct buffer {
uint64_t *buffer;
int max_size;
int min_fill_lvl;
uint64_t *first;
uint64_t *last;
int size;
semaphore produce;
semaphore consume;
} buffer;
void *producer();
void *consumer();
uint64_t get_rand_num();
void init_buffer();
void cleanup_buffer();
void put_buffer();
uint64_t get_buffer();
int exit1=0;
buffer buf;
int main(){
initialize(&buf.produce, 0);
initialize(&buf.consume, 0);
pthread_t producerThread;
pthread_t consumerThread;
printf("test");
pthread_create(&producerThread, NULL, producer, (void *) &buf);
pthread_create(&consumerThread, NULL, consumer, (void *) &buf);
vacate(&buf.produce);
pthread_join(producerThread, NULL);
pthread_join(consumerThread, NULL);
return 1;
}
void *producer(buffer *buf){
printf("in producer");
init_buffer(&buf, 2, 1);
while (1){
procure(&buf->produce);
uint64_t ret = get_rand_num();
put_buffer(&buf, ret);
vacate(&buf->consume);
}
cleanup_buffer(&buf);
pthread_exit(NULL);
}
void *consumer(buffer *buf){
printf("in consumer");
while (1){
procure(&buf->consume);
uint64_t ret = get_buffer(&buf);
printf("%i", (int) ret);
vacate(&buf->produce);
}
pthread_exit(NULL);
}
uint64_t get_rand_num(){
FILE *rand = NULL;
rand = fopen("/dev/random", "r");
uint64_t num;
//static const size_t size = sizeof(uint64_t);
fread(&num, sizeof(num), 1, rand); //returns -1 if fails i believe
//printf("%i\n", (int) num);
return num;
}
void init_buffer(buffer *buf, int max, int min){
buf->buffer = malloc(sizeof(uint64_t) * max);
buf->size = 0;
buf->min_fill_lvl = min;
buf->max_size = max;
}
void cleanup_buffer(buffer *buf){
free(&buf->buffer);
}
void put_buffer(buffer *buf, uint64_t *num){
if (buf->size < buf->max_size){
*(buf->last++) = *num;
buf->size++;
}
printf("successfully placed num in buffer");
}
uint64_t get_buffer(buffer *buf){
if ((buf->size - 1) <= buf->min_fill_lvl){
buf->size--;
int ret = *buf->first;
buf->first++;
return ret;
}
return 0;
}
This is my semaphore code:
// semaphore setup
void initialize(semaphore *sp, int startVal){
pthread_mutex_init(&sp->lock, NULL);
sp->vacancy = startVal; //starting value for semaphore
pthread_cond_init(&sp->condition, NULL);
}
//destroys semaphore
void destruct(semaphore *sp){
pthread_mutex_destroy(&sp->lock);
pthread_cond_destroy(&sp->condition);
}
//waits until semaphore is available
void procure(semaphore *sp){
pthread_mutex_lock(&sp->lock);
while(sp->vacancy <= 0){
pthread_cond_wait(&sp->condition, &sp->lock);
}
sp->vacancy--;
pthread_mutex_unlock(&sp->lock);
}
//increments vacancy value signalling that a position has been freed
void vacate(semaphore *sp){
pthread_mutex_lock(&sp->lock);
sp->vacancy++;
pthread_cond_signal(&sp->condition);
pthread_mutex_unlock(&sp->lock);
}

Resources