Tuesday, 17 April 2012

Common mistakes in C programming


Common mistakes about subfunction:

1. Formal parameter issues:
 
void GetMemory(char *p)
{
p = (char *)malloc(100);
}

void Test(void)
{
char *str = NULL;
GetMemory(str);  
strcpy(str, "hello world");
printf(str);
}
Using a pointer variable as formal parameter is dangerous, because formal parameter only passes the value. So it only pass the address. 

So when allocate memory to formal paramter or any other defined pointer variables in subfunction, it will disapear after the end of subfunction. Insteadly, we can achieve the same function by passing the pointer variable who points the pointer variable who is going to be allocated.
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
if(*p==NULL)
printf(" Memory allocation fails!\n ");
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");  
printf(str);   
}

2. Variable life in subfunction:

char *GetMemory(void)
{  
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str= GetMemory();   
printf(str);
}

This program may not print the string "hello world", because although GetMemory function can return the address of the string, but the content has been destroyed after the end of the subfunction.

Monday, 16 April 2012

Pointer variable


Usually, pointer variables are with type difinition like char *, int *, long *, and like that. So when you want to  do some operations, compiler will use sizeof(type) as the unit. For example:


#include "stdio.h"

main()
{
    int a[3]={4, 5, 6};
    int *point1;
    point1=a;
    point1=point1+1;
    printf("%d\n", *point1);
    getchar();
}

Result: 5

However, we can use void * to define a point variable without type. But this variable cannot be operated because of the uncertain length of this variable. So before operation, you have to cast the variable to a specific type to do the operations. For example:


#include "stdio.h"

main()
{
    int a[3]={4, 5, 6};
    void *point2;

    point2=a;

    point2=(char *)point2+1;
    printf("%d\n", *(int *)point2);
    point2=(char *)point2+1;
    printf("%d\n", *(int *)point2);
    point2=(char *)point2+1;
    printf("%d\n", *(int *)point2);
    point2=(char *)point2+1;
    printf("%d\n", *(int *)point2);

    getchar();
}
Result:
1280  --- 00000101  00000000
5
1536  --- 00000110  00000000
6



Reference:
[1] C语言深度解剖读书笔记之----C语言基础测试题, http://blog.csdn.net/feitianxuxue/article/details/7334929

Sunday, 25 March 2012

POSIX thread programming


Introduction:
Using thread has many benefits. They share the same resources of their calling process (parent process), like global variables, open files and so on. Also they have their own thread ID, stacks, and so on. For more information, please refer to the old article "Multitasking in Embedded Linux" and reference [1]. Here we focus on how to use it.

The simplest thread programming:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message(void *ptr)
{
    char *text;
    text=(char *)ptr;
    printf("%s \n", text);
}

main()
{
    pthread_t thread1, thread2;
    char *str1="I am thread1";
    char *str2="I am thread2";
    int T1ret, T2ret;

    /*Create two threads*/
    T1ret=pthread_create(&thread1, NULL, print_message, (void*) str1);
    T2ret=pthread_create(&thread2, NULL, print_message, (void*) str2);

    /*Wait for both threads to finish*/
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("T1 & T2 return: %d, %d\n", T1ret, T2ret);
}
Here we use pthread_create function to create a thread. There are four arguments in it.
First argument: used to return the thread ID.
Second argument: used to set the attributes of thread, like priority, schedule policy and so on. For detail, please refer to reference [1].
Third argument: assign the thread function which is the name of the function.
Four argument: used to pass value.

Usually at the end of the calling function, we use pthread_join(threadid, NULL) to wait for termination of that thread. This function is very important, because sometimes we need to allocate some memories for threads (refer to reference [2]). After all the threads terminates, we need to free these memories.


How to pass value to thread:

We can only use the fourth argument of pthread_create() to pass value. And it is declared as void *, so it is a totally free local variable. It can be converted to any type of variables by using casting.

Passing of pointer:
This is easy, because the fourth argument is a void pointer itself. So you can use the pointer as fourth argument. In thread, you need to cast it to the  type you like.

Passing of value:
Two ways to do this.
1. In thread_create() function, cast the variable to be passed to void * type. Then in thread, you can cast it to any type you want. For example:
rc=pthread_create(&threads[t], NULL, printhello. (void *)t);
In thread:
void *printhello(void *threadid)
{
    long taskid=(long)threadid;
    ...
}
2. Allocate a or several memories using malloc( ) function (refer to [2]) which return a pointer points to that location. Then you can use it like using pointer we talked in part 1. Here must remember to free the location using free( ) at the end of the function who called malloc( ).
long *taskids[NUM_THREADS];

for(t=0; t<NUM_THREADS; t++)
{
   taskids[t] = (long *) malloc(sizeof(long));
   *taskids[t] = t;
   printf("Creating thread %ld\n", t);
   rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
   ...
}

Passing of multiple parameters:
Use structure (struct) to this. Imagine yourself.
struct thread_data{
   int  thread_id;
   int  sum;
   char *message;
};

struct thread_data thread_data_array[NUM_THREADS];

void *PrintHello(void *threadarg)
{
   struct thread_data *my_data;
   ...
   my_data = (struct thread_data *) threadarg;
   taskid = my_data->thread_id;
   sum = my_data->sum;
   hello_msg = my_data->message;
   ...
}

int main (int argc, char *argv[])
{
   ...
   thread_data_array[t].thread_id = t;
   thread_data_array[t].sum = sum;
   thread_data_array[t].message = messages[t];
   rc = pthread_create(&threads[t], NULL, PrintHello, 
        (void *) &thread_data_array[t]);
   ...
}

Synchronization using Mutex:

Initialization of mutex:
pthread_mutex_t mutex1=PTHREAD_MUTEX_INITIALIZER;

Lock a mutex:
pthread_mutex_lock(&mutex1);

Unlock a mutex:
pthread_mutex_unlock(&mutex1);

Destroy a mutex:
pthread_mutex_destroy(&mutex1);

Set the stack size of thread:

pthread_attr_t attr;    // Here we define a attribute variable.

size_t mystacksize;
pthread_attr_getstacksize(&attr, &mystacksize);    // Here we get the stack size of variable attr. Remember it
                                                                             // belongs to variable attr, not the thread who calling it.

pthread_attr_setstacksize(&attr, mystacksize);     // Here we set the stack size of variable attr. Also remember
                                                                           // it belongs to variable attr.

Remember to put variable attr into the second argument of function pthread_create( ), like:
pthread_create(&threads[t], &attr, dowork, (void *) t);

At last, remember to destroy attr:
pthread_attr_destroy(&attr);

This procedure also can be applied to other attributes setting like joinable, scheduling, priority and so on.

References:
[2] malloc - Linux man page, http://linux.die.net/man/3/malloc
[6] pthread_attr_destroy( ) -- Destroy a thread attributes object, http://cursuri.cs.pub.ro/~apc/2003/resources/pthreads/uguide/users-g5.htm

Multitasking in Embedded Linux


Multitasking in Embedded Linux

In the computer field, "task" has the sense of a real-time application, as distinguished from process, which takes up space (memory), and execution time.

 A process, or task, can be seen as a set of allocated resources

Process switching makes big memory consumption. Because, when we created a new process, we need to create a process descriptor and allocate another memory region as its work space.

However, Thread allows you use the same memory in a process to work on, so you don't need to create an extra memory. So real-time linux use just one main process which includes threads to realize multitasking in embedded linux.

But there's more. Threads also happen to be extremely nimble. Compared to a standard fork(), they carry a lot less overhead. The kernel does not need to make a new independent copy of the process memory space, file descriptors, etc. That saves a lot of CPU time, making thread creation ten to a hundred times faster than new process creation. Because of this, you can use a whole bunch of threads and not worry too much about the CPU and memory overhead incurred. You don't have a big CPU hit the way you do with fork(). This means you can generally create threads whenever it makes sense in your program.
Threads differ from traditional multitasking operating system processes in that:
  • processes are typically mean time, while threads exist as subsets of a process
  • processes carry considerably more state information than threads, whereas multiple threads within a process share process state as well as memory and other resources.
  • processes have separate address spaces, whereas threads share their address space.
  • processes interact only through system-provided inter-process communication mechanisms.
  • Context switching between threads in the same process is typically faster than context switching between processes.

Saturday, 24 March 2012

How to create process in Linux


 In Linux, we use fork( ) to create a new process which is actually a copy of the calling process. The new process is a copy (the code after fork( ) function) of its parent  process. So if we do nothing about control flow, the child process will actually do the same thing the parent does.
Here we use the return value of fork( ) to distinguish the child and parent. In fact, the function fork( ) returns two values after it finishes. For the calling process (parent process), it returns the PID of child process in order that the calling process can manage it. However in child process, fork() will return 0. So by this, we can just use a "if(chpid)" to distinguish the twos and make them execute the different sequences.
Another very important thing is the fork only copy the code after the for( ) function. It does not care about the code above is except the definition part of variables.
#include <stdio.h>
#include <sched.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
    pid_t chpid;
    int fd, status, variable=9;
    char ch;
    fd=open("test.txt", O_RDONLY);
    chpid=fork();
    if(chpid!=0)
        wait(&status);
    else
    { /*Executed only by the child*/
        variable=42;
        close(fd);
        printf("The child has changed the variable to: %d\n", variable);
        printf("The child has also closed the file.\n");
        return(0);
    }
    printf("The variable is now: %d\n", variable);
    if(read(fd, &ch, 1)<0)
    {
        perror("READ failed");
        return(1);
    }
    printf("Read from the file: %s\n", &ch);
    return (0);
}
Above is common use case of fork( ). The wait( ) function is used by calling processes to wait for the state changes of their child processes, like resume, termination, restart and so on. For detail, please refer to reference [1].
References:
[1] wait - Linux man page, http://linux.die.net/man/2/wait

Thursday, 22 March 2012

Anonymous pipe and Named pipe


Introduction:
Anonymous pipe and Named pipe are usually used for communication between two different tasks.

Anonymous pipe:
It does not have name, and can be applied in the shell by using ' | '. It is unidirectional.
For example, p1 | p2
Here anonymous pipe usually is used in case of standard output and standard input which are related to the shell. So here you can use anonymous pipe ' | ' directly to transfer data from p1 to p2. So here must remember that the output and input are both for shell which means usually using functions printf() for output and scanf() for input or something like this.

Named pipe:
However, named pipe is related to a dev file which is more flexible. So in this case, you can transfer the data like writing/reading to/from file which is already familiar to you. We can create a pipe by using mkfifo /dev/mypipe where mkfifo is a new command, and in some old version of Linux you may use mknod p /dev/mypipe. But we recommend you use mkfifo /dev/mypipe.

Then we can write our applications like the following to test mypipe:
Read file:
//fifo_read.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void)
{
FILE *fp;
char buf[20];
/* Create the FIFO if it does not exist*/
umask(0);
mknod("mypipe", S_IFIO|0666, 0);
while(1)
{
fp=fopen("mypipe", "r");
fgets(buf, 20, fp);
printf("We received: %s\n", buf);
fclose(fp);
}
return(0);
}

Write file:
//fifo_write.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
FILE *fp;
if((fp=fopen("pipe", "w"))==NULL)
{
fprintf(stderr, "fopen caused an error\n");
exit(1);
}
fputs(argv[1], fp);
fclose(fp);
return(0);
}

Blocking and nonblocking:
Here we use fopen("mypipe", "r") open mypipe as a normal file which is default for blocking. So the after  writing, the program is blocked and wait for another program to read data. Similarly, after execute the read program, it will be blocked and wait until there is an another program to write in this buffer.

If it is nonblocking, then neither program will be waiting, they will just be executed until the end. But here we cannot use stream functions anymore, because they do not have the option for nonblocking, so you have to use file descriptors which is operated using system call (like operating drivers). So in file descriptor we can open the buffer as nonblocking as following:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int ifd;
...
ifd=open("/dev/mypipe", O_RDONLY | O_NONBLOCK);
...
read(ifd, buf, 20);

The differences between streams and file descriptors:


Warning:
Unless you really really have to use nonblocking buffer, please use stream to do blocking buffer.

Tuesday, 13 March 2012

Principle of Floating point


Introduction:
Compared to fixed point arithmetic, floating point allows us to use both larger scope of integer and fraction in a expression because of the floating exponent. 
A floating point memory block is composed of sign flag, exponent(2^e) and mantissa. The format is shown below.
64-bit floating point (double)

32-bit floating point (float)


  • We need the exponent part to be signed, so the compiler will subtract the q with a bias. The calculations are shown below.
e=q-bias

The number the format above represents is:
Here you must remember it is 1.M which is we call "significant figure" (有效数字). So when you do the some arithmetics, you have to ensure you shif the number to keep there is a "1" in the left of ".".

Precision of floating point:

Because the significant digits(有效数字) only have sizeof(M) bits, so the precision of floating point is only 2^(-sizeof(M)-1) (here we have a virtual bit). When a number is smaller than this precision, it will not be represented any more.

On the other hand, if the number exceeds 2^(sizeof(M)+1), its precision cannot be guaranteed anymore, which is also because the significant digits(有效数字) have limited bits (sizeof(M)). If a number exceeds the those significant digits, there is no enough room for the extra precision which will be missed. An example about this is shown below.

     #include <stdio.h>


     main()
     {
         int x;
         float y;

         x=1;
         while (x>0)
         {
             y=x+1;
             x=y;
         }

     }

This program will never end, because x will never overflow. When x exceeds the significant 
digits(有效数字), y cannot increase anymore. So this program will be stuck at x=16777216 (2^24).

The arithmetic (addition & subtraction) of floating point:
Here we talk about how to do addition and subtraction of floating point. As we know when we want dto do addition or subtraction of numbers with exponent, we have to align the exponent first. The floating point calculation needs the same operation.

So here we use shift on mantissa and increase on exponent to solve this problem. We start from the smaller number. When we shift the mantissa 1 bit to left, we increase the exponent by 1, until the exponent is equal to the bigger number. 

For example, we try to add 100.0 with 0.25 whose formats are "0 10000101 10010000000000000000000" and "0 01111101 00000000000000000000000" respectively. 

Then we start to shift 0.25:

0 01111101 00000000000000000000000 (original number)
0 01111110 10000000000000000000000 (right shift 1)
0 01111111 01000000000000000000000 (right shift 2)
0 10000000 00100000000000000000000 (right shift 3)
0 10000001 00010000000000000000000 (right shift 4)
0 10000010 00001000000000000000000 (right shift 5)
0 10000011 00000100000000000000000 (right shift 6)
0 10000100 00000010000000000000000 (right shift 7)
0 10000101 00000001000000000000000 (right shift 8)

Then we add 0 10000101 10010000000000000000000 with 0 10000101 00000001000000000000000.

                 0 10000101 10010000000000000000000
+ 0 10000101 00000001000000000000000
-----------------------------------------------------------
                 0 10000101 10010001000000000000000
                                           ||
                                     100.25



References:
[1] Chapter 7 -- floating point arithmetic, http://pages.cs.wisc.edu/~smoler/x86text/lect.notes/arith.flpt.html

Difference between "docker stop" and "docker kill"

 To stop a running container, you can use either "docker stop" or "docker kill" command to do so. Although it seems doin...