`
java-mans
  • 浏览: 11413488 次
文章分类
社区版块
存档分类
最新评论

多线程,它是让计算机更好用的东西,也是程序员最容易犯错的东西----小话c语言(13)

 
阅读更多

[Mac-10.7.1 Lion Intel-based x64 gcc4.2.1]


Q: c标准中包含线程操作么?

A:没有。


Q:给个mac下线程操作的例子吧。

A:创建线程的函数可以实用pthread_create,原型如下:

int  pthread_create(pthread_t *restrict thread,
         const pthread_attr_t *restrict attr, 
         void *(*start_routine)(void *),
         void *restrict arg);
thread是保存成功创建线程的ID; attr表示线程的相关属性,start_routine表示线程执行的函数, arg表示线程执行的使用的参数。

示例代码(保存为testForC.c):

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)      printf(#str" is %s\n", (str));

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret;
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    return 0;
}
运行:

可以看到,程序运行后然后很快就结束了,且没有任何输出。这是因为主线程过快结束导致结束了刚刚创建的子线程。


Q:如何让主线程不理解结束呢?

A:可以让主线程进入等待状态,加入while(1)循环让主线程一直等待。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret;
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    FOR_EVER();
    return 0;
}
运行结果:

上面是在子线程输出字符串的过程中截取的,子线程会一直运行下去,知道自己的循环退出。


Q:子线程运行的这么快,让它慢点行不?

A:在子线程的while循环中加个延迟1秒的函数,如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
        sleep(1);       // sleep for 1 second
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret;
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    FOR_EVER();
    return 0;
}

运行结果:

从实际运行可以看出,子线程每打印一行会延迟一下。


Q:主线程如何在规定的时间内干掉子线程?

A:主线程可以启动定时器,在指定时间内干掉子线程。

int  setitimer(int which,  const struct itimerval *restrict value,  struct itimerval *restrict ovalue);
参数which表示定时器类型,value表示定时器时间信息,ovalue可以设置为NULL.

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

pthread_t   thread;
int         should_loop = 1;

void    kill_son_thread(int arg)
{
    printf("now it will kill son thread...\n");
    pthread_cancel(thread);
    should_loop = 0;
}

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
        sleep(1);       // sleep for 1 second
    }
    return NULL;
}

int main()
{
    int ret;
    struct itimerval timer;
    
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    // set the timer
    timer.it_value.tv_sec = 5;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 5;
    timer.it_interval.tv_usec = 0;
    
    signal(SIGALRM, kill_son_thread);       // register a signal for timer action
    setitimer(ITIMER_REAL, &timer, NULL);   // start the timer
    while(should_loop)
        ;

    return 0;
}
运行结果:


可以看到,主线程大约5秒后干掉了子线程,然后结束了。


Q: pthread_exit不也可以退出线程么?

A:是的。不用定时器,子线程5秒后自动退出,代码如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

pthread_t   thread;
int         should_loop = 1;

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
        sleep(1);       // sleep for 1 second
        if(i == 6)
        {
            should_loop = 0;
            printf("[Son thread]: end...\n");
            pthread_exit(NULL);
        }
    }
    return NULL;
}

int main()
{
    int ret;
    
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    while(should_loop)
        ;
    printf("[Main thread]: end...\n");
    return 0;
}
运行结果:

Q:还有个函数,pthread_join的作用是什么?

A:它的作用是等待指定线程执行结束。它实现了线程之间的同步。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

pthread_t   thread;
int         should_loop = 1;

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        printf("thread: loop %d\n", i++);
        sleep(1);       // sleep for 1 second
        if(i == 6)
        {
            should_loop = 0;
            pthread_exit(NULL);
        }
    }
    return NULL;
}

int main()
{
    int ret;
    
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    pthread_join(thread, NULL);     // wait for the son thread's end
    printf("[Son thread]: end...\n");
    while(should_loop)
        ;
    printf("[Main thread]: end...\n");
    return 0;
}
运行结果:


Q:上面的情形,主线程需要等待子线程结束,如果主线程不必等待子线程结束,子线程为主线程提供必要的数据,二者同步运行,如何处理?

A:那么,可以使用互斥体、信号量等。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

pthread_t   thread;
int         should_loop = 1;
pthread_mutex_t mutex;
int         data[3];

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        pthread_mutex_lock(&mutex);
        data[0] = i;
        data[1] = i + 1;
        data[2] = i + 2;
        ++i;
        sleep(1);
        pthread_mutex_unlock(&mutex);      
    }
    return NULL;
}

int main()
{
    int ret;
    // create and init a mutex
    pthread_mutex_init(&mutex, NULL);
    
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(data[0] > 3)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]);
        pthread_mutex_unlock(&mutex);
    }
    pthread_mutex_destroy(&mutex);
    printf("[Main thread]: end...\n");
    
    return 0;
}
上面的代码,主线程从全局数据data中读取数据,子线程大约每1秒更新下data中的数据,当data[0]的值大于3的时候主线程退出。

运行结果:


Q:还有种类型pthread_cond_t,它和pthread_mutex_t有什么区别?

A:前者是在某种情况下设定的"互斥体",后者可以当成无条件的互斥体;例子如下,

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>

#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));
#define PRINT_STR(str)          printf(#str" is %s\n", (str));
#define FOR_EVER()              { while(1) ; }

pthread_t   thread;
int         should_loop = 1;
pthread_mutex_t mutex;
int         data[3];
pthread_cond_t  cond;

void    *thread_one_func(void *args)
{
    int i = 1;
    while (i > 0)
    {
        pthread_mutex_lock(&mutex);
        data[0] = i;
        data[1] = i + 1;
        data[2] = i + 2;
        if(data[0] % 2 == 0)
            pthread_cond_signal(&cond);
        ++i;
        sleep(1);
        pthread_mutex_unlock(&mutex);      
    }
    return NULL;
}

int main()
{
    int ret;
    // create and init a mutex
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    
    ret = pthread_create(&thread, NULL, thread_one_func, NULL);
    if(ret < 0)
    {
        perror("pthread_create error");
        return -1;
    }
    
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(data[0] > 6)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_cond_wait(&cond, &mutex);
            
        printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]);
        pthread_mutex_unlock(&mutex);
    }
    
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    printf("[Main thread]: end...\n");
    
    return 0;
}
上面的代码,主线程当发现data[0]大于6时就退出;小于6的时候,等待cond的状态变化;子线程会更新data数组中的数值,且当data[0]是偶数的时候就激活等待cond的线程(主线程),二者实现同步和互斥。

运行效果:

对于同步互斥,semaphore也可以实现; sem_open, sem_wait等等是操作它的函数,这里不再一一介绍。


xichen

2012-5-19 15:46:26



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics