一、线程的概念
线程是指进程内部的一个执行单元,也称为轻量级进程,它和进程一样可以独立执行、拥有独立的栈空间、程序计数器和寄存器等,但是多个线程可以共享进程的资源,如内存空间、文件、I/O。线程的创建和销毁都比进程更加的轻便快捷,因此多线程成为了提高系统性能和程序效率的一种重要方式。
二、线程的创建
Linux提供了几种方式创建线程:pthread_create()、clone()等。其中pthread_create()是比较常用的一个函数,其函数原型如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
它的参数依次为:
1、指向线程标识符的指针;
2、线程属性,NULL表示使用默认属性;
3、指向函数的指针,该函数是新线程的入口地址;
4、函数的参数。
下面是一个简单的例子:
#include#include #include void *print_message_function(void *ptr); int main() { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int ret1, ret2; // 创建线程1 ret1 = pthread_create(&thread1, NULL, print_message_function, (void *) message1); if (ret1 != 0) { printf("Create thread 1 failed!\n"); exit(1); } // 创建线程2 ret2 = pthread_create(&thread2, NULL, print_message_function, (void *) message2); if (ret2 != 0) { printf("Create thread 2 failed!\n"); exit(1); } pthread_join(thread1, NULL); pthread_join(thread2, NULL); printf("Main function exits!\n"); return 0; } void *print_message_function(void *ptr) { char *message = (char *) ptr; printf("%s\n", message); }
在上面的例子中,我们使用pthread_create()函数创建了2个线程,并传入一个字符串作为线程函数的参数。然后使用pthread_join()函数等待线程结束。
三、线程的同步
线程之间的同步通常需要互斥量、条件变量等机制。比如常用的互斥量pthread_mutex_t可以用来保护共享资源,pthread_cond_t则可以用来进行线程的条件等待与唤醒。
下面是一个使用互斥量保护共享资源的例子:
#include#include #include #define THREAD_NUM 5 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int sum = 0; void *thread_function(void *arg); int main() { pthread_t threads[THREAD_NUM]; // 创建多个线程 for (int i = 0; i < THREAD_NUM; i++) { pthread_create(&threads[i], NULL, thread_function, NULL); } // 等待所有线程结束 for (int i = 0; i < THREAD_NUM; i++) { pthread_join(threads[i], NULL); } printf("Sum = %d\n", sum); return 0; } void *thread_function(void *arg) { int i; for (i = 0; i < 1000; i++) { pthread_mutex_lock(&mutex); sum++; pthread_mutex_unlock(&mutex); } pthread_exit(NULL); }
在这个例子中,我们使用pthread_mutex_t来保护sum这个共享资源,多个线程会去累加这个值。由于多个线程同时访问sum,如果没有互斥保护,会产生竞争状态,导致结果不正确。因此我们使用互斥量对共享资源进行保护,保证线程之间的同步。
四、线程的销毁
线程的销毁通常是在线程函数中通过pthread_exit()函数进行,也可以使用pthread_cancel()函数强制取消线程。同时可以使用pthread_join()函数等待线程结束,防止进程过早退出,导致线程没有执行完毕。
下面是一个使用pthread_cancel()函数强制取消线程的例子:
#include#include #include void *thread_function(void *arg); int main() { pthread_t thread_id; int ret; // 创建线程 ret = pthread_create(&thread_id, NULL, thread_function, NULL); if (ret != 0) { printf("Create thread failed!\n"); exit(1); } // 睡眠 5 秒 sleep(5); // 强制杀死线程 pthread_cancel(thread_id); printf("Main function exits!\n"); return 0; } void *thread_function(void *arg) { int i; // 设置取消状态 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); // 设置取消类型 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); for (i = 0; ; i++) { printf("Thread running...\n"); sleep(1); } pthread_exit(NULL); }
在上面的例子中,我们使用了pthread_cancel()函数强制取消线程。同时在线程函数中设置了取消状态和取消类型。
五、线程的属性
线程的属性可以用来调整线程的优先级、栈大小等。pthread_attr_t是线程属性的类型,Linux提供了一些函数来进行线程属性的设置和获取,如pthread_attr_init()、pthread_attr_setstacksize()、pthread_attr_getschedpolicy()等。
下面是一个设置线程栈大小的例子:
#include#include #include void *thread_function(void *arg); int main() { pthread_t thread_id; pthread_attr_t attr; size_t stacksize; int ret; // 初始化线程属性 pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &stacksize); printf("Default stack size = %d KB\n", (int) stacksize / 1024); // 设置线程栈大小 pthread_attr_setstacksize(&attr, 1024 * 1024); pthread_attr_getstacksize(&attr, &stacksize); printf("New stack size = %d KB\n", (int) stacksize / 1024); // 创建线程 ret = pthread_create(&thread_id, &attr, thread_function, NULL); if (ret != 0) { printf("Create thread failed!\n"); exit(1); } // 等待线程结束 pthread_join(thread_id, NULL); printf("Main function exits!\n"); return 0; } void *thread_function(void *arg) { int i; for (i = 0; i < 10; i++) { printf("Thread running...\n"); sleep(1); } pthread_exit(NULL); }
在上面的例子中,我们使用了pthread_attr_setstacksize()函数设置了线程的栈大小为1MB。
六、总结
本文介绍了Linux下创建线程的方法及相关知识。具体来说,我们讲解了线程的概念、创建、同步、销毁和属性等内容。通过本文的学习,读者可以掌握如何使用Linux提供的相关函数来创建线程,并进行进一步的开发。