Linux线程
首先 Linux 并不存在真正的线程,Linux 的线程是使用进程模拟的。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
线程与进程的区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
1)一个程序至少有一个进程,一个进程至少有一个线程;
2)线程的划分尺度小于进程,使得多线程程序的并发性高;
3)进程在执行过程中拥有独立的内存单元,而多个线程共享内存,
从而极大地提高了程序的运行效率;
4)线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制;
5)多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
使用线程的理由
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式,并且它具有更加方便的线程间通信方式。
线程的创建
在 Linux 中创建线程非常简单,使用系统提供的接口很容易就能完成。
注意编译程序的时候因为使用到了系统提供的线程库函数,因此编译链接的时候需要使用-pthread 链接线程库
gcc test.c -o test -pthread
示例
#include <stdio.h> #include <unistd.h> #include <pthread.h> static void *thread_start(void *arg) { char buff[] = "child thread exit!!\n"; pthread_t tid; //调用pthread_self获取自身的线程tid,并打印参数 tid = pthread_self(); while (1){ printf("child thread id:[%ld], parm[%s]\n", tid, (char*)arg); sleep(1); } pthread_exit(NULL); } int main(int argc, char *argv[]) { int ret; pthread_t tid; char buff[] = "first thread"; //使用 pthread_create 创建子线程,线程运行函数为thread_start函数 //并为子线程传入参数buff,获取线程tid,线程属性并没有设置,置空 ret = pthread_create(&tid, NULL, thread_start, (void *)buff); if (0 != ret){ printf("pthread_create error!!\n"); return -1; } while (1){ printf("main thread:[%ld]\n", tid); sleep(1); } pthread_cancel(tid); //被动 return 0; }
线程同步
线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点。linux 下提供了多种方式来处理线程同步,最常用的是互斥锁。
互斥锁示例
#include <stdio.h> #include <unistd.h> #include <pthread.h> pthread_mutex_t mutex; void *thread_start(void *arg) { int *i = (int *)arg; //调用pthread_detach来分离线程 pthread_detach(pthread_self()); while (1){ pthread_mutex_lock(&mutex); if (*i < 100){ usleep(100); printf("child i = [%d]\n", (*i)++); }else { pthread_mutex_unlock(&mutex); pthread_exit(NULL); } pthread_mutex_unlock(&mutex); } return NULL; } int main(int argc, char *argv[]) { pthread_t tid; int i = 0; pthread_mutex_init(&mutex, NULL); int ret = pthread_create(&tid, NULL, thread_start, (void *)&i); if (0 != ret){ printf("pthread_create error!!\n"); return -1; } while (1){ pthread_mutex_lock(&mutex); if (i < 100){ usleep(100); printf("main i = [%d]\n", i++); }else { pthread_mutex_unlock(&mutex); pthread_exit(NULL); } pthread_mutex_unlock(&mutex); } return 0; }
条件变量
与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
示例
#include <stdio.h> #include <unistd.h> #include <string.h> #include <pthread.h> #include <stdlib.h> pthread_mutex_t mutex; pthread_cond_t cond; int cond_global = 0; void *thread_start(void *arg) { int *i = (int *)arg; while (1){ pthread_mutex_lock(&mutex); while (cond_global == 0){ pthread_cond_wait(&cond, &mutex); } cond_global = 0; if (*i < 100){ usleep(100); printf("child i = [%d]\n", (*i)++); pthread_mutex_unlock(&mutex); pthread_cond_signal(&cond); }else{ return 0; } } return NULL; } int main(int argc, char *argv[]) { pthread_t tid; int i = 0; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); int ret = pthread_create(&tid, NULL, thread_start, ( void *)&i); if (ret != 0){ return -1; } while (1){ pthread_mutex_lock(&mutex); while (cond_global == 1){ pthread_cond_wait(&cond, &mutex); } cond_global = 1; if (i < 100){ usleep(100); printf("main i:[%d]\n", i++); pthread_mutex_unlock(&mutex); pthread_cond_signal(&cond); }else{ return 0; } } return 0; }