Linux多线程编程(初步)

1.Linux进程与线程

Linux进程创建一个新线程时,线程将拥有自己的栈(因为线程有自己的局部变量),但与它的创建者共享全局变量、文件描述符、信号句柄和当前目录状态。

Linux通过fork创建子进程与创建线程之间是有区别的:fork创建出该进程的一份拷贝,这个新进程拥有自己的变量和自己的PID,它的时间调度是独立的,它的执行几乎完全独立于父进程。

进程可以看成一个资源的基本单位,而线程是程序调度的基本单位,一个进程内部的线程之间共享进程获得的时间片。

2.线程的基本函数

1.线程创建:

int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

参数说明:

thread:指向pthread_create类型的指针,用于引用新创建的线程。

attr:用于设置线程的属性,一般不需要特殊的属性,所以可以简单地设置为NULL。

(*start_routine)(void ):传递新线程所要执行的函数地址。

arg:新线程所要执行的函数的参数。

调用如果成功,则返回值是0,如果失败则返回错误代码。
2.线程终止

void pthread_exit(void *retval);

参数说明:

retval:返回指针,指向线程向要返回的某个对象。

线程通过调用pthread_exit函数终止执行,并返回一个指向某对象的指针。注意:绝不能用它返回一个指向局部变量的指针,因为线程调用该函数后,这个局部变量就不存在了,这将引起严重的程序漏洞。

3.线程同步

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

参数说明:

th:挂起当前的线程,直到th指定的线程终止为止。

thread_return:一个指针,指向另一个指针,而后者指向线程的返回值。

例:

#include
#include
#include
#include
#include
#include
void *func1(void *arg){
    int i=*(int *)arg;
    printf("pthread%d start\n",i);
    while(1){
        printf("pthread%d ing\n",i);
        sleep(1);
    }
    printf("pthread%d end\n",i);
    return NULL;
}
int main(){
    pthread_t id1,id2;
    int i1=1;
    int i2=2;
    if(pthread_create(&id1,NULL,func1,&i1) !=0){
        printf("error is %s",strerror(errno));
    }
    if(pthread_create(&id2,NULL,func1,&i2) !=0){
        printf("error is %s",strerror(errno));
    }
    while(1);
    return 0;
}

结果为:

xin@xin-Lenovo-V3000:~/code/thread/thread1$ ./thread1
pthread1 start
pthread1 ing
pthread2 start
pthread2 ing
pthread2 ing
pthread1 ing
pthread1 ing
pthread2 ing
pthread2 ing
pthread1 ing
pthread1 ing
pthread2 ing
pthread2 ing
pthread1 ing
pthread2 ing
...

我们可以看到,两个线程在同步执行。
当i1,i2为局部变量时候,代码需要改进,因为执行:

pthread_create(&id2,NULL,func1,&i2);

这段话的时候,i2地址已经被回收。
改进:

#include
#include
#include
#include
#include
#include
void *func1(void *arg){
    int *p=(int *)arg;
    int i=*p;
    free(p);
    printf("pthread%d start\n",i);
    while(1){
        printf("pthread%d ing\n",i);
        sleep(1);
    }
    printf("pthread%d end\n",i);
    return NULL;
}
void creat_thread(){
    pthread_t id1,id2;
    //static int i1=1;
    //static int i2=2;
    int *i1=malloc(sizeof(int));
    *i1=1;
    int *i2=malloc(sizeof(int));
    *i2=2;
    if(pthread_create(&id1,NULL,func1,i1) !=0){
        printf("error is %s",strerror(errno));
    }
    if(pthread_create(&id2,NULL,func1,i2) !=0){
        printf("error is %s",strerror(errno));
    }
}
int main(){
    creat_thread();
    while(1);
    return 0;
}

为i1,i2分配内存空间,或者声明为静态变量都可以。
接下来我们继续改进代码,对线程做进一步的探讨。

#include
#include
#include
#include
#include
#include
void *func1(void *arg){
    int *p=(int *)arg;
    int i=*p;
    free(p);
    printf("pthread%d start\n",i);
    int a=0;
    for(a=7;a>0;a--){//a a在进程的栈里边,每个线程都有a,互不影响
        printf("pthread%d ing\n",i);
        sleep(1);
    }
    printf("pthread%d end\n",i);
    return NULL;
}
int main(){
    pthread_t id1,id2;
    //static int i1=1;
    //static int i2=2;
    int *i1=malloc(sizeof(int));
    *i1=1;
    int *i2=malloc(sizeof(int));
    *i2=2;
    if(pthread_create(&id1,NULL,func1,i1) !=0){
        printf("error is %s",strerror(errno));
    }
    if(pthread_create(&id2,NULL,func1,i2) !=0){
        printf("error is %s",strerror(errno));
    }
    pthread_join(id1,NULL);//主线程挂起等待thread退出
    pthread_join(id2,NULL);//主线程挂起等待thread退出
    printf("main end\n");
    return 0;
}

我们关注a是共有的还是每个线程独有的。

xin@xin-Lenovo-V3000:~/code/thread/thread1$ ./pth
pthread1 start
pthread1 ing
pthread2 start
pthread2 ing
pthread1 ing
pthread2 ing
pthread1 ing
pthread2 ing
pthread2 ing
pthread1 ing
pthread2 ing
pthread1 ing
pthread2 ing
pthread1 ing
pthread2 ing
pthread1 ing
pthread2 end
pthread1 end
main end

我们发现每个线程都享有a变量。for循环输出各执行了7次。
注意:在链接时候加-lpthread选项,表示链接上libpthread.so库。

3.线程同步(互斥锁)

通过上边代码,我们发现:两个线程之间执行顺序是无序的,怎么才能让一个线程执行结束,再执行另一个线程呢?我们可以用互斥锁,在互斥锁中间的代码是原子操作,不能被打断。

#include 
#include 
#include 
#include 
#include 
#include 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//初始化了一个MUTEX锁
void *func1(void *arg)
{
        pthread_mutex_lock(&mutex);//给mutex加锁,这是一条原子操作,不可能出现两个线程同时执行这个代码
        int *a = (int *) arg;
        printf("thread%d start\n", *a);
        int i;
        for (i = 0; i < 5; i++)
        {
                printf("thread%d is running\n", *a);
                sleep(1);
        }
        printf("thread%d end\n", *a);
        pthread_mutex_unlock(&mutex);//给mutex解锁
        pthread_exit(NULL);
}

int main(int arg, char * args[])
{
        printf("process start\n");
        pthread_t thr_d1, thr_d2;
        int i[2];
        i[0] = 1;
        i[1] = 2;


        pthread_create(&thr_d1, NULL, func1, &i[0]);
        pthread_create(&thr_d2, NULL, func1, &i[1]);
        pthread_join(thr_d1, NULL);
        pthread_join(thr_d2, NULL);

        printf("process end\n");
        return 0;
}

结果:

xin@xin-Lenovo-V3000:~/code/thread/thread2$ ./thread6
process start
thread1 start
thread1 is running
thread1 is running
thread1 is running
thread1 is running
thread1 is running
thread1 end
thread2 start
thread2 is running
thread2 is running
thread2 is running
thread2 is running
thread2 is running
thread2 end
process end

线程1执行完之后,线程2执行。

你可能感兴趣的:(linux)