免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 926 | 回复: 0
打印 上一主题 下一主题

Beginning Linux Programming (3) (thread) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-24 00:48 |只看该作者 |倒序浏览
It's important to be clear about the differences between the fork system call and the creation of thread.

When a process executes a fork call, a new copy og the process is created with its own variables and its own PID. This new process is scheduled independently, and (in general) executes almost independently of the process that created it.

When we create a new thread in a process, the new thread of execution gets its own stack (hence local variables) but shares global varibales, file descriptors, signal handlers, and its current directory state with the process that created it.

★A simple thread program.
#include
int pthread_create(pthread_t *thread, pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg) ;

void pthread_exit(void *retval);

int pthread_join(pthread_t th, void **pthread_return) ;

pthread_join is the thread equivalent of wait that processes use to collect child processes.

#include
#include
#include
#include

void *thread_function(void *arg);
char message[] = "Hello World";

int main()
{
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined, it returned %s\n", (char *)thread_result);
    printf("Message is now %s\n", message);
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg)
{
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(3);
    strcpy(message, "Bye!");
    pthread_exit("Thank you for the CPU time");
}
cc -D_REENTRANT -I/usr/include/ntpl thread1.c -o thread1 -L/usr/lib/ntpl -lpthread

---------------------------------------------------------------------------------
★Simultaneous Execution
#include
#include
#include
#include

void *thread_function(void *arg);
int run_now = 1;
char message[] = "Hello World";

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    int print_count1 = 0;
    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    while(print_count1++
    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    int print_count2 = 0;
    while(print_count2++
    sleep(3);
}
it will be very inefficient program that does what is known as a polling between the two threads.

---------------------------------------------------------------------------------
★Synchroniztion With Semaphores
There are two sets of interface functions for semaphores: One is taken from POSIX Realtime Extensions and used for threads, and the other is known as System V semaphores, which are commonly used for process synchronization.

Binary Semaphore and Counting Semaphore:
four basic function used in threads.

#include
int sem_init(sem_t *sem, int pshared, unsigned int value) ;
pshared option: controls the type of semaphor.
pshared :  0 ---> semaphore is local to the current process
         else---> semaphore will be shared between processes

int sem_post(sem_t *sem) ;
int sem_wait(sem_t *sem) ;
int sem_destroy(sem_t *sem) ;

Semaphore.c (example)
#include
#include
#include
#include
#include
void *thread_function(void *arg);
sem_t bin_sem;

#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    res = sem_init(&bin_sem, 0, 0);
    if (res != 0) {
        perror("Semaphore initialization failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    printf("Input some text. Enter 'end' to finish\n");
    while(strncmp("end", work_area, 3) != 0) {
        fgets(work_area, WORK_SIZE, stdin);
        sem_post(&bin_sem);
    }
    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    sem_destroy(&bin_sem);
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    sem_wait(&bin_sem);
    while(strncmp("end", work_area, 3) != 0)
{
        printf("You input %d characters\n", strlen(work_area) -1);
        sem_wait(&bin_sem);
    }
    pthread_exit(NULL);
}
改变程序的适当代码:
。。。。。
    printf("Input some text. Enter 'end' to finish\n");
    while(strncmp("end", work_area, 3) != 0)
{
      if (strncmp(work_area, "FAST", 4) == 0)
   {
    sem_post(&bin_sem);
        strcpy(work_area, "Wheeeeeee...");
      } else {
        fgets(work_area, WORK_SIZE, stdin);
      }
      sem_post(&bin_sem);
}
printf("\nWaiting for thread to finish...\n");
。。。。。。

看到结果:
Input some text. Enter 'end' to finish
FAST
You input 11 characters
You input 11 characters
You input 11 characters

END
You input 3 characters
end
Waiting for thread to finish...
Thread joined

---------------------
原因分析:
问题出在 our program was relying on text input from the program so long that there was time for the other thread to count the words before the main thread was ever ready to give it more words to count.  When we tried to give it two different sets of words to count in quick succession (FAST from the key board and Weee.... automatically), there was no time for the second thread to execute. Howerver the second have been incremented more than once, so the counter thread just kept couting the words and decreasing the semaphore until it became zero again.



---------------------------------------------------------------------------------
★Synchroniztion With Mutexes

allow the programmer to "lock" an object so that only one thread can access it.

#include

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_muteattr_t &mutexattr)
int pthread_mutex_lock(pthread_mutex_t *mutex) ;
int pthread_mutex_unlock(pthread_mutex_t *mutex) ;
int pthread_mutex_destory(pthread_mutex_t *mutex) ;

mutexattr: by default is "fast" 可能导致死锁 或者是多次加锁问题

#include
#include
#include
#include
#include
void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    res = pthread_mutex_init(&work_mutex, NULL);
    if (res != 0) {
        perror("Mutex initialization failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    pthread_mutex_lock(&work_mutex);
    printf("Input some text. Enter 'end' to finish\n");
    while(!time_to_exit) {
        fgets(work_area, WORK_SIZE, stdin);
        pthread_mutex_unlock(&work_mutex);
        while(1) {
            pthread_mutex_lock(&work_mutex);
            if (work_area[0] != '\0') {
                pthread_mutex_unlock(&work_mutex);
                sleep(1);
            }
            else {
                break;
            }
        }
    }
    pthread_mutex_unlock(&work_mutex);
    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    pthread_mutex_destroy(&work_mutex);
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    sleep(1);
    pthread_mutex_lock(&work_mutex);
    while(strncmp("end", work_area, 3) != 0) {
        printf("You input %d characters\n", strlen(work_area) -1);
        work_area[0] = '\0';
        pthread_mutex_unlock(&work_mutex);
        sleep(1);
        pthread_mutex_lock(&work_mutex);
        while (work_area[0] == '\0' ) {
            pthread_mutex_unlock(&work_mutex);
            sleep(1);
            pthread_mutex_lock(&work_mutex);
        }
    }
    time_to_exit = 1;
    work_area[0] = '\0';

    pthread_mutex_unlock(&work_mutex);
    pthread_exit(0);
}

-------------------------------------------------------------------------------
★Thread Attributes

#include
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr) ;

there are addtional functions that we can call to set different behaviors.

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
int pthread_attr_setstacksize(pthread_attr_t *attr, int scope);
int pthread_attr_getstacksize(const pthread_attr_t *attr, int *scope);

detachedstate
This attribute allows us to avoid the need for threads to re−join. Like most of these _set functions, it takes a
pointer to the attribute and a flag to determine the state required. The two possible flag values for
pthread_attr_setdetachstate are PTHREAD_CREATE_JOINABLE and PTHREAD_CREATE_DETACHED.
By default, the attribute will have value PTHREAD_CREATE_JOINABLE so that we should allow the two
threads to join. If the state is set to PTHREAD_CREATE_DETACHED, then you cannot call pthread_join to
recover the exit state of another thread.
schedpolicy
This controls how threads are scheduled. The options are SCHED_OTHER, SCHED_RP and SCHED_FIFO.
By default, the attribute is SCHED_OTHER. The other two types of scheduling are only available to
processes running with superuser permissions, as they both have real time scheduling but with slightly
different behavior. SCHED_RR uses a round−robin scheduling scheme, and SCHED_FIFO uses a 'first in,
first out' policy. Discussion of these is beyond the scope of this book.
schedparam
This is a partner to schedpolicy and allows control over the scheduling of threads running with schedule
policy SCHED_OTHER. We will have a look at an example of this in a short while.
inheritsched
This attribute takes two possible values, PTHREAD_EXPLICIT_SCHED and
PTHREAD_INHERIT_SCHED. By default, the value is PTHREAD_EXPLICIT_SCHED, which means
scheduling is explicitly set by the attributes. By setting it to PTHREAD_INHERIT_SCHED, a new thread
will instead use the parameters that its creator thread was using.
scope
This attribute controls how scheduling of a thread is calculated. Since Linux only currently supports the value
PTHREAD_SCOPE_SYSTEM, we will not look at this further here.
stacksize
This attribute controls the thread creation stack size, set in bytes. This is part of the 'optional' section of the
specification and is only supported on implementations where _POSIX_THREAD_ATTR_STACKSIZE is
defined. Linux implements threads with a large amount of stack by default, so the feature is generally
redundant on Linux and consequently not implemented.

----------------------------------------------------------------------------------
Example Setting the Detached State Attribute

#include
#include
#include
#include
void *thread_function(void *arg);
char message[] = "Hello World";
int thread_finished = 0;
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    pthread_attr_t thread_attr;
    res = pthread_attr_init(&thread_attr);
    if (res != 0) {
        perror("Attribute creation failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (res != 0) {
        perror("Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    (void)pthread_attr_destroy(&thread_attr);
    while(!thread_finished) {
        printf("Waiting for thread to say it's finished...\n");
        sleep(1);
    }

    printf("Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(4);
    printf("Second thread setting finished flag, and exiting now\n");
    thread_finished = 1;
    pthread_exit(NULL);
}

--------------------------------------------------------
Example Scheduling
#include
#include
#include
#include
void *thread_function(void *arg);
char message[] = "Hello World";
int thread_finished = 0;
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    pthread_attr_t thread_attr;
   int max_priority;
    int min_priority;

    struct sched_param scheduling_value;
    res = pthread_attr_init(&thread_attr);
    if (res != 0) {
        perror("Attribute creation failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setschedpolicy(&thread_attr, SCHED_OTHER);
    if (res != 0) {
        perror("Setting schedpolicy failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (res != 0) {
        perror("Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    max_priority = sched_get_priority_max(SCHED_OTHER);
    min_priority = sched_get_priority_min(SCHED_OTHER);
    scheduling_value.sched_priority = min_priority;
    res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
    if (res != 0) {
        perror("Setting schedpolicy failed");
        exit(EXIT_FAILURE);
    }
    (void)pthread_attr_destroy(&thread_attr);
    while(!thread_finished) {
        printf("Waiting for thread to say it's finished...\n");
        sleep(1);
    }
    printf("Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(4);
    printf("Second thread setting finished flag, and exiting now\n");
    thread_finished = 1;
    pthread_exit(NULL);
}

-------------------------------------------------------------------------------
★Canceling a Thread

the fuction to request a thread to terminate:
#include
int pthread_cancel( phtread_t thread) ;

This is pretty straightforward: Given a thread identifier, we can request that it be cancelled.On receiving end of the cancel request, things are slightly compilcated. A thread can set its cancel state using pthread_setcancelstate.

int pthread_setcancelstate( int state , int *oldstate) ;

state : PTHREAD_CANCLE_ENABLE --> allow it to receive cancel requests
        PTHREAD_CANCLE_DISABLE--> causes them to be ignored

oldstate : allows the previous state to be retrieved. (可传递null 如果不需要)

如果cancel的请求被接受, 选择cancel的类型

int pthread_setcanceltype( int type , int *oldtype) ;

type : PTHREAD_CANCLE_ASYNCHRONOUS 取消动作立即执行
       PTHREAD_CANCLE_DEFERRRED    取消不立即执行, 直到线程执行了函数 pthread_join,
pthread_cond_wait,  pthread_cond_timedwait ,  pthread_testcancel , sem_waitm or  sigwait.

example Cancelling a thread :

#include
#include
#include
#include
void *thread_function(void *arg);
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    sleep(3);
    printf("Canceling thread...\n");
    res = pthread_cancel(a_thread);
    if (res != 0) {
        perror("Thread cancelation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    int i, res, j;
    res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (res != 0) {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    if (res != 0) {
        perror("Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf("thread_function is running\n");
    for(i = 0; i


-------------------------------------------------------------------------------
★ Thread Adundance

#include
#include
#include
#include
#define NUM_THREADS 6
void *thread_function(void *arg);
int main() {
    int res;
    pthread_t a_thread[NUM_THREADS];
    void *thread_result;
    int lots_of_threads;
    for(lots_of_threads = 0; lots_of_threads
        res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)&lots_of_threads);
        if (res != 0) {
            perror("Thread creation failed");
            exit(EXIT_FAILURE);
        }
        sleep(1);
    }
    printf("Waiting for threads to finish...\n");
    for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
        res = pthread_join(a_thread[lots_of_threads], &thread_result);

        if (res == 0) {
            printf("Picked up a thread\n");
        }
        else {
            perror("pthread_join failed");
        }
    }
    printf("All done\n");
    exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
    int my_number = *(int *)arg;
    int rand_num;
    printf("thread_function is running. Argument was %d\n", my_number);
    rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));

    sleep(rand_num);
    printf("Bye from %d\n", my_number);
    pthread_exit(NULL);
}
---------------------------------------------------------------------------














本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94518/showart_1941348.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP