In accordance with its thread scheduler can be divided into user-level threads and kernel-level thread two kinds
User-level threads to solve the main problem is that context switching, its scheduling algorithms and scheduling of all selection decisions on their own by the user, it does not require specific kernel support at run time;
we used is the basic user-level threads, so we only summarize POSIX the interface provides user-level threads;
function associated with the basic thread operations:
1 the end of the thread to establish
two mutually exclusive and synchronization thread
3 using the signal to control the amount of thread
basic properties of four thread arranged
substantially thread operations:
function | Explanation |
---|---|
pthread_create() | Create a thread starts running thread related functions, the end of the running thread exit |
pthread_eixt() | Because exit () is used to end the process, so you need to use a specific function of the end of the thread |
pthread_join() | Suspend the current thread, waiting for blocking the end of the thread, if the thread has ended immediately return 0 = success |
pthread_cancel() | Send a termination signal to the thread thread, it returns 0 on success, but success does not mean that thread will terminate |
pthread_testcancel() | Create a cancellation point in a place that does not contain a cancellation point, but they need to cancel points, so that does not contain a code execution thread cancellation point in response to a cancellation request. |
pthread_setcancelstate() | This thread is provided in response to signals Cancel |
pthread_setcanceltype() | Setting canceled state continues to run to the next point and then withdraw or cancel the implementation of the action immediately cancel |
pthread_setcancel() | Set status canceled |
Mutual exclusion and synchronization mechanisms basic functions
function | Explanation |
---|---|
pthread_mutex_init() | Mutex initialization |
pthread_mutex_lock() | Mutex lock, if you try to lock the mutex has been locked to the blockage becomes available |
pthread_mutex_trylock() | Non-blocking lock mutex |
pthread_mutex_unlock() | Release mutex |
pthread_mutex_destory() | Mutex destructor |
Semaphore thread control (default unnamed semaphore)
function | Explanation |
---|---|
sem_init (not) | Anonymous initialize a semaphore is positioned in the sem |
sem_wait () | The operation signal minus 1, if the current value of the semaphore into the obstruction 0, an atomic operation |
sem_trywait () | If the semaphore's current value is 0 errors returned instead of blocking call (errno = EAGAIN), in fact, is sem_wait () is a non-blocking version |
sem_post () | To the semaphore value plus 1, which is a "atomic operation", i.e., while doing the same amount was added to a 1 signal, the operation of the two threads is not conflict |
sem_getvalue(sval) | Sem points to the amount of the signal is placed on the current value of the integer directed sval |
sem_destory (free) | Anonymous destroyed by the semaphore pointed to sem |
Thread related property configuration function
function | Explanation |
---|---|
pthread_attr_init() | The initial configuration of a thread object attributes, you need to remove an existing property with pthread_attr_destroy function |
pthread_attr_setscope() | Set thread attributes |
pthread_attr_setschedparam() | Set thread priority |
pthread_attr_getschedparam() | Get the Thread Priority |
Establish basic thread running pthread_create
-
/* thread.c */
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
#define THREAD_NUMBER 3 /*线程数*/
-
#define REPEAT_NUMBER 5 /*每个线程中的小任务数*/
-
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
-
//
-
void *thrd_func(void *arg) {
-
/* 线程函数例程 */
-
int thrd_num = (int)arg;
-
int delay_time = 0;
-
int count = 0;
-
printf("Thread %d is starting\n", thrd_num);
-
for (count = 0; count < REPEAT_NUMBER; count++) {
-
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
-
sleep(delay_time);
-
printf("\tThread %d: job %d delay = %d\n",
-
thrd_num, count, delay_time);
-
}
-
printf("Thread %d finished\n", thrd_num);
-
pthread_exit(NULL);
-
}
-
int main(void) {
-
pthread_t thread[THREAD_NUMBER];
-
int no = 0, res;
-
void * thrd_ret;
-
srand(time(NULL));
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
/* 创建多线程 */
-
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
-
if (res != 0) {
-
printf("Create thread %d failed\n", no);
-
exit(res);
-
}
-
}
-
printf("Create treads success\n Waiting for threads to finish...\n");
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
/* 等待线程结束 */
-
res = pthread_join(thread[no], &thrd_ret);
-
if (!res) {
-
printf("Thread %d joined\n", no);
-
} else {
-
printf("Thread %d join failed\n", no);
-
}
-
}
-
return 0;
-
}
- Routine 3 cycles to establish three threads, and use pthread_join function in order to wait for the end of the thread;
Thread using rand () Gets a random value random sleep five times, after random thread of execution will be finished first;
result:
-
$ gcc thread.c -lpthread
-
$ ./a.out
-
Create treads success
-
Waiting for threads to finish...
-
Thread 0 is starting
-
Thread 1 is starting
-
Thread 2 is starting
-
Thread 1: job 0 delay = 2
-
Thread 1: job 1 delay = 2
-
Thread 0: job 0 delay = 8
-
Thread 2: job 0 delay = 10
-
Thread 2: job 1 delay = 3
-
Thread 1: job 2 delay = 10
-
Thread 0: job 1 delay = 8
-
Thread 0: job 2 delay = 3
-
Thread 0: job 3 delay = 1
-
Thread 2: job 2 delay = 8
-
Thread 1: job 3 delay = 8
-
Thread 1: job 4 delay = 1
-
Thread 1 finished
-
Thread 2: job 3 delay = 6
-
Thread 0: job 4 delay = 7
-
Thread 0 finished
-
Thread 0 joined
-
Thread 1 joined
-
Thread 2: job 4 delay = 10
-
Thread 2 finished
-
Thread 2 joined
- Can be seen, thread 1 performed prior to thread 0, but pthread_join calls in chronological order, wait thread 0 execution;
Since the thread 1, it has already ended, so the thread 0 is pthread_join wait time, thread 1 has ended, just waiting to thread 1, direct return;
Mutual exclusion and synchronization thread execution pthread_mutex_lock
Mutex increase in the above procedure
-
/*thread_mutex.c*/
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
#define THREAD_NUMBER 3 /* 线程数 */
-
#define REPEAT_NUMBER 3 /* 每个线程的小任务数 */
-
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
-
pthread_mutex_t mutex;
-
void *thrd_func(void *arg) {
-
int thrd_num = (int)arg;
-
int delay_time = 0, count = 0;
-
int res;
-
/* 互斥锁上锁 */
-
res = pthread_mutex_lock(&mutex);
-
if (res) {
-
printf("Thread %d lock failed\n", thrd_num);
-
pthread_exit(NULL);
-
}
-
printf("Thread %d is starting\n", thrd_num);
-
for (count = 0; count < REPEAT_NUMBER; count++) {
-
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
-
sleep(delay_time);
-
printf("\tThread %d: job %d delay = %d\n",
-
thrd_num, count, delay_time);
-
}
-
printf("Thread %d finished\n", thrd_num);
-
pthread_exit(NULL);
-
}
-
int main(void) {
-
pthread_t thread[THREAD_NUMBER];
-
int no = 0, res;
-
void * thrd_ret;
-
srand(time(NULL));
-
/* 互斥锁初始化 */
-
pthread_mutex_init(&mutex, NULL);
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
-
if (res != 0) {
-
printf("Create thread %d failed\n", no);
-
exit(res);
-
}
-
}
-
printf("Create treads success\n Waiting for threads to finish...\n");
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
res = pthread_join(thread[no], &thrd_ret);
-
if (!res) {
-
printf("Thread %d joined\n", no);
-
} else {
-
printf("Thread %d join failed\n", no);
-
}
-
}
-
/****互斥锁解锁***/
-
pthread_mutex_unlock(&mutex);
-
pthread_mutex_destroy(&mutex);
-
return 0;
-
}
- Added directly above routine pthread_mutex_t synchronization lock;
Join in the thread, so the program is executed thread program;
calls pthread_mutex_lock locked, found locked when entering the waiting, waiting for re-locked after the lock is released again;
so-threaded programs loaded into the waiting queue, waiting to continue successfully unlocked executing program code;
operating results
-
$gcc thread_mutex.c -lpthread
-
$ ./a.out
-
Create treads success
-
Waiting for threads to finish...
-
Thread 0 is starting
-
Thread 0: job 0 delay = 9
-
Thread 0: job 1 delay = 4
-
Thread 0: job 2 delay = 7
-
Thread 0 finished
-
Thread 0 joined
-
Thread 1 is starting
-
Thread 1: job 0 delay = 6
-
Thread 1: job 1 delay = 4
-
Thread 1: job 2 delay = 7
-
Thread 1 finished
-
Thread 1 joined
-
Thread 2 is starting
-
Thread 2: job 0 delay = 3
-
Thread 2: job 1 delay = 1
-
Thread 2: job 2 delay = 6
-
Thread 2 finished
-
Thread 2 joined
- 1 routines with different execution result, the thread program is loaded into the queue can not be executed immediately, it waits to successfully locked;
After locking, the program continues to execute threads, lock execution;
the case of such threads are executed in sequence often occur in actual use scenarios;
usage scenarios:
when the user logs on to obtain the secret key to continue getting the basic information of the user; to wait when we can proceed to obtain user information log on after the end of the thread thread
needs to call two threads, if it is: threadLogin (), threadGetInfo () ; you can have two kinds of ways:
1 At this point you can use a mutex while disposable End call threadLogin () and threadGetInfo ();
2 may not be used of course call threadGetInfo (mutex directly after threadLogin () in the login authentication success);
in contrast, a clearer display mode logic, add code readability scalability.
Controlling the order of execution threads using semaphores sem_post
Modify the above routine, using the above pthread_mutex_lock mutex control thread execution order,
using the additional control in a thread of execution order;
-
/* thread_sem.c */
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
#include <semaphore.h>
-
#define THREAD_NUMBER 3
-
#define REPEAT_NUMBER 3
-
#define DELAY_TIME_LEVELS 10.0
-
sem_t sem[THREAD_NUMBER];
-
void * thrd_func(void *arg) {
-
int thrd_num = (int)arg;
-
int delay_time = 0;
-
int count = 0;
-
sem_wait(&sem[thrd_num]);
-
printf("Thread %d is starting\n", thrd_num);
-
for (count = 0; count < REPEAT_NUMBER; count++) {
-
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
-
sleep(delay_time);
-
printf("\tThread %d: job %d delay = %d\n", thrd_num, count, delay_time);
-
}
-
printf("Thread %d finished\n", thrd_num);
-
pthread_exit(NULL);
-
}
-
int main(void) {
-
pthread_t thread[THREAD_NUMBER];
-
int no = 0, res;
-
void * thrd_ret;
-
srand(time(NULL));
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
sem_init(&sem[no], 0, 0);
-
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
-
if (res != 0) {
-
printf("Create thread %d failed\n", no);
-
exit(res);
-
}
-
}
-
printf("Create treads success\n Waiting for threads to finish...\n");
-
sem_post(&sem[THREAD_NUMBER - 1]);
-
for (no = THREAD_NUMBER - 1; no >= 0; no--) {
-
res = pthread_join(thread[no], &thrd_ret);
-
if (!res) {
-
printf("Thread %d joined\n", no);
-
} else {
-
printf("Thread %d join failed\n", no);
-
}
-
sem_post(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]);
-
}
-
for (no = 0; no < THREAD_NUMBER; no++) {
-
sem_destroy(&sem[no]);
-
}
-
return 0;
-
}
The results still build three threads, each thread to sleep long random execution:
-
$ gcc thread_sem.c -lpthread
-
$ ./a.out
-
Create treads success
-
Waiting for threads to finish...
-
Thread 2 is starting
-
Thread 2: job 0 delay = 9
-
Thread 2: job 1 delay = 9
-
Thread 2: job 2 delay = 5
-
Thread 2 finished
-
Thread 2 joined
-
Thread 1 is starting
-
Thread 1: job 0 delay = 5
-
Thread 1: job 1 delay = 7
-
Thread 1: job 2 delay = 4
-
Thread 1 finished
-
Thread 1 joined
-
Thread 0 is starting
-
Thread 0: job 0 delay = 3
-
Thread 0: job 1 delay = 9
-
Thread 0: job 2 delay = 8
-
Thread 0 finished
-
Thread 0 joined
The results of the first two routines are very similar, except that textbooks be executed only in reverse;
it this way than using a mutex in fact, basically the same amount of code readability comparable;
The basic properties pthread_attr_setscope thread
Properties generally provided:
a binding property
separation property
3 Address Stack
4 Stack size
5 Priority
About binding property is bound to a kernel thread;
separate property mainly whether immediately release the corresponding memory after the talk thread;
-
/* thread_attr.c */
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <pthread.h>
-
#define THREAD_NUMBER 1
-
#define REPEAT_NUMBER 3
-
#define DELAY_TIME_LEVELS 10.0
-
int finish_flag = 0;
-
void * thrd_func(void * arg){
-
int delay_time = 0;
-
int count = 0;
-
printf("Thread is starting\n");
-
for (count = 0; count < REPEAT_NUMBER; count++) {
-
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
-
sleep(delay_time);
-
printf("\tThread : job %d delay = %d\n", count, delay_time);
-
}
-
printf("Thread finished\n");
-
finish_flag = 1;
-
pthread_exit(NULL);
-
}
-
int main(void) {
-
pthread_t thread;
-
pthread_attr_t attr;
-
int res = 0;
-
srand(time(NULL));
-
res = pthread_attr_init(&attr);
-
if (res != 0) {
-
printf("Create attribute failed\n");
-
exit(res);
-
}
-
res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
-
res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
if (res != 0) {
-
printf("Setting attribute failed\n");
-
exit(res);
-
}
-
res = pthread_create(&thread, &attr, thrd_func, NULL);
-
if (res != 0) {
-
printf("Create thread failed\n");
-
exit(res);
-
}
-
pthread_attr_destroy(&attr);
-
printf("Create tread success\n");
-
while(!finish_flag){
-
printf("Waiting for thread to finish...\n");
-
sleep(2);
-
}
-
return 0;
-
}
Use $ free run commands before and after viewing memory usage before and after the discovery:
memory is released immediately after the end of the thread;
in fact, attribute general thread can directly use the system default properties;
use on threads, nearly so;
all the routines from : "embedded Linux application development standards tutorial"