Archive

Nowadays is very common to see dual-core or quad-core CPUs, but there are still systems with one single core.
In this post, I want to about the very basis of concurrency, a brief introduction to this world, so some descriptions will be so so simple, but real world is a little bit more complex.

In multi-core or multi-CPU systems, the operating system (OS) distributes tasks within our CPUs, and we can run several tasks at the same time, but we have been enjoying multitasking for decades, long before multi-core appeared, so, how is it possible? Let’s think about single-core systems, they can only perform one task, but the operating system distributes the CPU control along all tasks very fast so it makes us think all of them are running at the same time. So single-core CPUs usually have one execution thread, dual-core system, will have two execution threads, so they can perform two tasks at the same time. But don’t worry about how it is distributed, because the operating system does it for you.

We’ve seen the OS is smart enough to take advantage of our CPUs or CPU cores, so does it have any sense to make our application use several cores, or make our application run two things at the same time?
Of course it does, let’s see some examples:

Imagine a GUI program performing a heavy task. While this task is running, we may want to give the user some little control to cancel the process, for example, or to carry on using our software. We can run the heavy task in one thread and the GUI in another one.

A server which attends several clients simultaneously.

A program which does intense calculations, if we have dual-core, it can be twice faster

In the last case, we must think about something a little bit. Distributing tasks in time takes some time for the OS, so we must make sure the time we save (separating the process in several threads) is bigger than the time the OS wastes managing the new tasks and sometimes we must put all the results of all individual threads together (and it takes time too).
We may think it will be valid only for multi-core processors but the time taken by our tasks may vary depending on what we are doing, for example, calculations take all CPU Time, but if we access external devices (keyboard, screen, hard disk, USB, etc), even access a file, it makes our process wait for the data and while we are waiting, the CPU is wasting time, so we can take this time to perform calculations for some other process, and it is valid even on single-core CPUs. Sometimes running a tasks in two threads can squeeze our CPU better than one thread using CPU while the other thread is just waiting for data an vice-versa.

Ok, before playing a little bit with it we must know there are some ways to do that. We can create several processes, it’s like running some programs at the same time, and the other way is creating threads. The difference is that processes must store in RAM memory, data and stack among other things, and some threads can share code and data, so only stack and a little information about execution status belongs to each thread exclusively. We can say process initiates also a single execution thread.

Let’s code a bit, we will use pthreads (POSIX threads):

1234567891011121314151617181920212223242526272829

#include <stdio.h>#include <stdlib.h>#include <pthread.h>

void*newtask(void*null){printf("Hello world! I'm a new thread\n");
sleep(1);printf("Goodbye world! I'm a thread about to die\n");
pthread_exit(NULL);}

printf("Main process about to finish.\n");/* Last thing that main() should do */
pthread_exit(NULL);}

This example can be compiled including pthread library, this way:

$ gcc -o onethread onethread.c -lpthread

We are just executing a program that creates another thread that performs a task, this task is writing a couple of messages on screen and wait a bit between them. We can see a result like this:

Main process just started.
Main process about to finish.
Hello world! I’m a new thread
[ wait for a second ]
Goodbye world! I’m a thread about to die

The first two messages belongs to the main thread, one when it stats and the other one when it ends, but before ending we are invoking the other thread that writes the other two messages. As we can see, each thread is executed independently, but to see it a bit more clearer, let’s see the next code:

for(i=0; i<10;++i){
usleep(100);printf(" MAIN: %d\n", i);}printf("Main process about to finish.\n");/* Last thing that main() should do */
pthread_exit(NULL);}

What we’ve done is that the main thread (MAIN) and secondary thread (THREAD) will write on screen several messages inside a for loop. They will be counting from 0 to 9, but waiting a little bit between each writing (instead of doing heavier time eater tasks we simulate them with sleeps).

The code we iterate is between LOOP…END LOOP. What we see right before (my_loop) is a label, just to give a name to that loop, and reference it. In this example, we simply increment counter variable, and with a condition we can exit the loop when this variable reaches the value 10. We won’t see the 10 because we leave the loop before printing this number.

Let’s do something a bit more complicated, we will record scores in a game, this game will be a skill test to do in the shortest time as possible, hopscotch jumping and with obstacles. There are two types of penalty, touch the ground with both feet and hitting an obstacle. At the end of the tests the results will be written on a table, and a score will be assigned, this score will be also stored on that table to avoid calculating it each time.

Must have in mind something. With the CURSOR we will go through the result of a SELECT statement, and we’ll have to store the values returned for each row in variables (that’s why I declared v_name, v_time, v_penalty1 and v_penalty2). In the end, each iteration will do a SELECT Name, Time, Penalty1, Penalty2 INTO v_name, v_time, v_penalty1, v_penalty2 WHERE …, so we’ll have these variables filled with the data obtained for each row in each iteration. That’s DECLARE xxx CURSOR FOR SELECT …

We must put a finish condition, usually we will finish the loop when no more results are found, that’s why we use DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=1, In this case, we will set fin to 1 when no more rows are found.

Inside the loop, we will test the value of this variable and LEAVE the loop if fin is set to 1, it’s automatically done when we reach the condition given before.

One step more, let’s create a function to assign the scores to each one of the runners with a formula. For example, if Time is the time taken in seconds, 500-Time will be the initial score and we will take away 5*penalty+3*penalty2. So:

Of course, as I said in the beginning of this post we must see if there is no other method to do the same. I know using MySQL loops is amazing, as I always say with regex, but there may be faster methods, like:

But, we can do more things with the loop, for example, if the time is greater than 250, we can swap penalties, editing the loop, with a IF statement, we could also do it in the procedure, but that’s an option.

A small example (or not so small) come to mi mind. Imagine we have a user system. Each user has its information stored in three tables: one for login, password and access info; another one for profile data and the last one for permissions. In this cas, all tables except permission table has one row per user. But as the permission table stores the access level for a user and another object (maybe a web page), and one single user can have permissions over several pages, there may be some rows for one user.

We will also have a table to store messages between users.

We will also have pages, these pages will be objects in our system, and users can see , edit, create derivates and delete them (if they are allowed to). A hierarchy may exist with pages, so we can have child pages, but when we create a new page:

If a user is allowed to edit a parent page, will be allowed to edit the new child page

If a user could create derivatives in a parent, will be also allowed in the child

If a user was allowd to edit and create derivatives in the parent page, will also be allowed to remove the child page.

We will have to send a message to the user telling him or her, about the new page and what is allowed to do with it.

We also have these procedures and functions:

can_create_derivatives(user, page) – It will return TRUE if the user can create derivatives

can_edit(user, page) – It will do the same, but with edit permission

new_permission(user, page, permission) – It will allow the user to do what permission says with this page

message(from, to, message) – Send a message to a user.

Functions can_create_derivatives() and can_edit() seem to be easy to understand, but what they do internally is far more complicated. It’s done by a colleague and I don’t want to fight with it. The same with new_permission() (it can insert rows or updates existent ones) or message(), it can send notifications and create a job to send real e-mail, so our procedure may be something like: