Need advice to provide accurate time delay in C

This is a discussion on Need advice to provide accurate time delay in C within the C Programming forums, part of the General Programming Boards category; Can I ask if anyone can advise me on the command to provide accurate timing delay in C which which ...

  1. #1
    Registered User
    Join Date
    Feb 2008
    Posts
    12

    Need advice to provide accurate time delay in C

    Can I ask if anyone can advise me on the command to provide accurate timing delay in C which which I can use for my multithreading application using pthread?

    I've tried generating a "for" loop which is not ideal in my case because the busy loop just takes up the processor and stops other processes from running in parallel. Also I've tried the "usleep" command but usleep(1) (presumably time delay of 1 microsec) is too slow. Can I ask what usleep is exactly doing - is it a kind of busy loop as well? If not, can I check if there is a command call "nanosleep"?

    Please kindly advise if there is a nice way to generate this delay which does not require any processing (so that I can use it for the multithreading) and fast enough (preferably in nanosecs).

    Thanks for your help in advance.

    Peck

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    there is a nanosleep(), but neither of nanosleep or usleep are guaranteed to sleep for EXACTLY the amount of time you ask for - only to sleep for AT LEAST that amount of time - and in the implementation of these, the code is likely to round the sleep amount to some granularity.

    The next comment is that Linux (which I presume you are using) is not a real-time OS, so you will most likely NEVER get very precise timing from it.

    Why do you need such precise timing? What are you trying to do?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Feb 2008
    Posts
    12
    Thanks for the response. In fact I do not need the precise timing on the delay. I just need a simple "sleep" delay which does not take up much of the processor.

    I'm using it for my multithreading application - where in the first thread I'll need a time delay to enable some samples to be collected and in the second thread I'll store the sampled data. This delay is neccessary but not time critical. The main problem is to ensure that the processor is free to perform the 2nd thread during the time delay (in 1st thread).

    Any suggestion will be greatly appreciated. Thanks.

    Peck

  4. #4
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,263
    That's like trying to control the weather on Mars.

    Unless you're running on a real time operating system, even the best timing functions will only guarantee that they will wait AT LEAST as long as the specified time period. They could wait much longer, due to system load.

    Accuracy and precision aren't the same thing. A function like nanosleep() is very precise (you can specify very fine-grained delays) but not accurate (you're still at the mercy of the system).

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Unless you're running on a single-CPU system, I would guess that a wait-loop should suffice if you only need to wait for extremely small increments. Otherwise you'll have to use one of the various sleep functions provided by the OS.

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by cpjust View Post
    Unless you're running on a single-CPU system, I would guess that a wait-loop should suffice if you only need to wait for extremely small increments. Otherwise you'll have to use one of the various sleep functions provided by the OS.
    But that also prevents second thread from running, so you aren't really achieving anything.

    Using delays in threads is definitely not a good plan. Use semaphores or other methods to signal data ready.

    If you are collecting data in one thread and storing it in a second thread, do something like this:
    Using two identical blocks for sampled data:
    Thread 1: wait for semaphore. When semaphore allows the thread to run, save a block of data.
    Thread 2: store data in block 1. When the block is full, switch to second block, and signal semaphore for thread 1 to store the data.

    Of course, on a single core processor system (or a multi(core) processor system where there are more runnable threads than processor(core)s), this is going to be less efficient than running a single thread using asynchronous storing.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by matsp View Post
    But that also prevents second thread from running, so you aren't really achieving anything.
    Not if the other thread is running on a different CPU.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by cpjust View Post
    Not if the other thread is running on a different CPU.
    Sorry, I misread your reply to say "if you are on", not "unless you are on" single core CPU.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Feb 2008
    Posts
    12
    Thanks for the suggestion. However, I'm not using the time delay to synchronise between the two threads. In fact, I've used the pthread_cond_wait() and pthread_cond_signal() for that purpose.

    The problem which I'm having is to generate a "idle" time delay within the 1st thread (as needed by the hardware when receiving the data) and while it is idling, the processor will allow the 2nd thread to perform its task.

    Unfortunately, although I would like to use a simple "busy loop" to generate the delay, this has caused a significant "jamming" problem as seen in the data results. I'm hoping to insert a line which allows the processor to idle for less than 1 microsec.

    Any suggestions will be appreciated.

    Peck

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It would probably help a lot if you could post your code.

    But in general, no, you can't delay for 1 microsecond. You will get something bigger than that. usleep(1) will sleep for a clock-tick, which is more likely to be 1 millisecond.

    However, with correctly designed thread handling, there should be no need to make one thread sleep to make the other one run. Having said that, there is absolutely no chance that your other thread will always run, whatever you do in your "write data thread".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    22,920
    I would think something like an event is better for this task. Unless you run on a dual core.
    If it's single core, the thread that checks the hardware can set the event as it receives the event from the hardware. The other thread will wait for the event to become signaled. The hardware thread will reset the event once it's done with its work.

    This should guarantee that it can work with getting the data until it's finished.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Elysia View Post
    I would think something like an event is better for this task. Unless you run on a dual core.
    If it's single core, the thread that checks the hardware can set the event as it receives the event from the hardware. The other thread will wait for the event to become signaled. The hardware thread will reset the event once it's done with its work.

    This should guarantee that it can work with getting the data until it's finished.
    I believe that events and pthread conditions are pretty much identical.

    However, as I understand the original poster, it's a problem of "whilst the write-thread is running, the thread to sampling the data is not being run, so we need a way to reschedule the sampling thread". This sort of "make the scheduler do what I want" is always going to fail in a longer term, because although you can put your thread to sleep, there's absolutely no guarantee that the scheduler doesn't find some other "good" thread to run at that precise point in time. It's got no chance of working!

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Feb 2008
    Posts
    12
    Can anyone kindly advise me if I've done something wrong in my program as shown below. A time delay (I used "usleep" here) is necessary to cycle through the different channels of the ADC (device to read the samples). When the bin is full, the writeval() thread will start writing the data to a logfile.

    Can I ask if there is a better way to replace the usleep command so that it will not create a busy loop and allows the processor to run the writeval() while the readval() continues reading the samples at the same time?

    The results I've got when I used this program - there is a time delay whenever the bin is full and starts writing the data. I suspect it's due to the usleep. Notice that I did not use mutex here but using memcpy. Am I doing something wrong here?

    Any help will be greatly appreciated.

    Peck

    Code:
    /*****************************************************
    * DESCRIPTION:
    *   This is a multi-thread example to read and write samples to a output
    *   file. There are two threads in this program : a readval and writeval threads.
    *
    *   The readval thread reads in samples from a device and when the number of
    *   samples reaches a specific size, it is flagged to the 2nd thread and the 
    *   existing data is copied to a new buffer before the 1st thread reads again.
    *
    *   The writeval thread writes the binary data to a log file.
    *******************************************************/
    
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <errno.h>
    #include <time.h>
    #include <pthread.h>
    
    pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond_sample_limit = PTHREAD_COND_INITIALIZER;
    
    void *readval(void *arg);
    void *writeval(void *arg);
    void *writetext(void *arg);
    
    #define NUM_THREADS	2
    #define NCH		3
    #define NSAMPLES	50000
    char filename1[50];
    int data[NSAMPLES][NCH];
    int data1[NSAMPLES][NCH];
    int flag = 1;
    int nCount = 0;
    int totCount = 0;
    
    //************************** Main Program ***********************************
    
    int main(int argc, char *argv[])
    {
    	char *dirname ="/mnt/cf/";
    	char *input_fname = "zzzbinG.log";
    	char *output_fname = "zzztextG.log";
    	
    	strcpy(filename1,dirname);
    	strcat(filename1,input_fname);
    
    	pthread_t threads[NUM_THREADS];
      
    	if (pthread_create(&threads[1], NULL, writeval, NULL)) {
     	printf("Error creating writing_thread.\n"); abort();
    	}
    
    	if (pthread_create(&threads[0], NULL, readval, NULL)) {
    	printf("Error creating reading_thread.\n"); abort();
    	}
    
    
    	/* Join all threads upon completion*/
    	int tmp;
    	for (tmp = 0; tmp < NUM_THREADS; tmp++) {
    	pthread_join(threads[tmp], NULL);
    	}
    	printf ("Main():\t All processes for %d threads closed. Done.\n\n", NUM_THREADS);
    
    	pthread_mutex_destroy(&mymutex);
    	pthread_cond_destroy(&cond_sample_limit);
    
    	fflush(stdout);
    	return 0;
    }
    // ==================== Reading Values from Device =====================
    void *readval(void *arg)
    {
    	int ch,t;
    	int etime = 50;
    
    	int channel[] = {0x8400,
                     	0xc400,
    		 	0x9400};
    
    	time_t	prevTime;
        	time_t	endTime;
    	prevTime = time( NULL );
    	while ( time( NULL ) == prevTime ) {;}
    	endTime = prevTime + etime;
    
    	while (time( NULL ) <= endTime) {
    
    		// Time delay required
    		for (ch=0; ch < NCH; ch++) {
    			data1[nCount][ch]=ADC_TxRx(channel[ch]);
    			usleep(1);
    		}
    		nCount++;
    
    		// Store data when bin is full
    		if (nCount == NSAMPLES) {
    			memcpy(data, data1, NSAMPLES*NCH *sizeof(int));
    			nCount=0;
    			flag=2;
    			
    			pthread_cond_broadcast(&cond_sample_limit);
    		}
    	}
    	flag=0;
    	pthread_exit(NULL);
    	close(gpio_fd);
    	fflush(stdout);
    }
    
    // ====================== Writing Binaries to File =======================
    void *writeval(void *arg) 
    {
    	size_t obj_size=sizeof(int);
    	size_t obj_cnt=sizeof(data)/sizeof(int);
    
    	FILE *p_file1;
    	p_file1=fopen(filename1,"a");
    
    	while (flag!=0) {
    		pthread_cond_wait(&cond_sample_limit, &mymutex);		
    		fwrite(&data, obj_size,obj_cnt, p_file1);
    	}
    
    	fflush(p_file1);
    	fclose(p_file1);
      	pthread_exit(NULL);
    }

  14. #14
    Registered User
    Join Date
    Apr 2007
    Posts
    51
    You could have a semaphore for the data and a flag that is set as to whether the 2nd thread has saved the data.

    The first thread processes the data and sets a flag that is shared. The first thread always checks the flag before running again. The second thread clears the flag once it has completed it's work on the data. In between checks, you could use nanosleeps or whatever sleep time is close.

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,691
    Problems I see:
    1) pthread_exit() doesn't return, close(gpio_fd) never called - just remove all calls to pthread_exit()
    2) Undefined behavior due to calling pthread_cond_wait() without locking mutex first
    3) Unsynchronized access to globals by readval() - mutex is never locked.
    4) Remove all calls to time() and usleep() - they aren't needed - use a better "stopping strategy" in readval()

    Here is a very simple implementation of Salem's suggestion from your previous thread: http://cboard.cprogramming.com/c-programming/101883-need-help-multithreading-receiving-storing-data-parallel.html#post743534
    Code:
    #include <stdio.h>
    #include <pthread.h>
    
    void* read_thread(void *arg);
    void* write_thread(void *arg);
    
    #define NCH             3
    #define WRITE_SZ        512 // # of bytes to accumulate before writing
    #define NSAMPLES        (WRITE_SZ / (NCH * sizeof(int)))
    #define SETS_TO_READ    5 // # of times to read NSAMPLES before quiting
    
    int g_buff1[NSAMPLES * NCH];
    int g_buff2[NSAMPLES * NCH];
    int *g_write_buff;
    int g_exit = 0;
    const char *g_output_file = "samples.txt";
    pthread_mutex_t g_mux = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;
    
    // simulate reading from ADC
    int ADC_TxRx(int ch)
    {
        static int s_ADC_data[NCH] = {0, 0, 0};
        return ++s_ADC_data[ch];
    }//ADC_TxRx
    
    int main(void)
    {
        pthread_t reader_thread, 
                  writer_thread;
    
        pthread_create(&writer_thread, NULL, &write_thread, NULL);
        pthread_create(&reader_thread, NULL, &read_thread, NULL); 
    
        pthread_join(reader_thread, NULL);
        pthread_join(writer_thread, NULL);
    
        printf("main(): All threads done.\n"
               "SETS_TO_READ = %d, NSAMPLES = %d, WRITE_SZ = %d\n", 
               SETS_TO_READ, NSAMPLES, WRITE_SZ);
    
        pthread_mutex_destroy(&g_mux);
        pthread_cond_destroy(&g_cond);
    
        return 0;
    }//main
    
    void* read_thread(void *arg)
    {
        int *cur_buff = g_buff1,
            *last_buff = g_buff2,
            *tmp_buff;
        int nSet;
    
        for (nSet = 0; nSet < SETS_TO_READ; ++nSet)
        {
            int nSample, i = 0;
            for (nSample = 0; nSample < NSAMPLES; ++nSample)
            {
                int ch;
                for (ch = 0; ch < NCH; ++ch) 
                    cur_buff[i++] = ADC_TxRx(ch);
            }//for
    
            // signal write thread to write g_write_buff
            pthread_mutex_lock(&g_mux);
            {
                g_write_buff = cur_buff;
                pthread_cond_broadcast(&g_cond);
            }//mutex block
            pthread_mutex_unlock(&g_mux);
    
            // swap buffers
            tmp_buff = cur_buff;
            cur_buff = last_buff;
            last_buff = tmp_buff;
        }//for
    
        // signal write thread to exit
        pthread_mutex_lock(&g_mux);
        {
            g_exit = 1;
            pthread_cond_broadcast(&g_cond);
        }//mutex block
        pthread_mutex_unlock(&g_mux);
    
        return 0;
    }//read_thread
    
    void* write_thread(void *arg) 
    {
        FILE *out = fopen(g_output_file, "w");
    
        pthread_mutex_lock(&g_mux);
        {
            for (;;)
            {
                int nSample, i;
    
                pthread_cond_wait(&g_cond, &g_mux);
                if (g_exit)
                    break;
    
                i = 0;
                for (nSample = 0; nSample < NSAMPLES; ++nSample)
                {
                    fprintf(out, "%d, %d, %d\n", 
                            g_write_buff[i++], // 3 channels per sample
                            g_write_buff[i++],
                            g_write_buff[i++]);
                }//for
                
                // ensure writes go to disk
                fflush(out);
            }//for
        }//mutex block
        pthread_mutex_unlock(&g_mux);
    
        fclose(out);
        return 0;
    }//write_thread
    This is as simple as it gets (minus error checking). The downside is that the reading bandwidth is limited by the writing bandwidth, as I mentioned in the previous thread.

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. time class
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 12-11-2001, 10:12 PM
  2. Time Delay doesn't work!
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 11-17-2001, 01:12 PM
  3. How can I create a time delay?
    By Guideon72 in forum C Programming
    Replies: 14
    Last Post: 10-25-2001, 03:28 PM
  4. time delay function available?
    By cUser in forum C Programming
    Replies: 3
    Last Post: 10-01-2001, 01:14 AM
  5. relating date....
    By Prakash in forum C Programming
    Replies: 3
    Last Post: 09-19-2001, 10:08 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21