看到前边多进程的时候就知道肯定后边有多线程,否则只用进程就太重型了。但是使用线程就要碰到数据共享的问题了。
创建线程
C的线程库是pthread.h
,使用这个库来操作线程。
使用线程的步骤是:
- 创建需要在线程中运行的函数
- 创建一个结构
pthread_t
pthread_create()
创建并立刻运行线程
- 主线程需要监听线程,不能立刻结束,否则尚未运行完的线程也没了
由于线程库不是C标准库,需要在使用的时候使用参数-lpthread
链接该库。
来创建两个在线程里执行的函数,注意,这种函数的返回值必须是 void*
,也就是通用指针类型:
void *overtime(void *a) {
int i = 0;
for (; i < 10; i++) {
sleep(1);
puts("still overtime .....");
}
return NULL;
}
void *update_git(void *b) {
int j;
for (j = 0; j < 10; j++) {
sleep(1);
puts("don't forget to learn coding...");
}
return NULL;
}
然后创建结构pthread_t
并运行:
pthread_t thread0;
pthread_t thread1;
//线程需要运行的函数传递给pthread_create
if (pthread_create(&thread0, NULL, overtime, NULL) == -1) {
error("can't create thread0");
}
if (pthread_create(&thread1, NULL, update_git, NULL) == -1) {
error("can't create thread1");
}
之后监听线程是否结束。
//用一个变量接收线程函数返回的指针
void *result;
//pthread_join通过监听线程返回值的方式等待线程
if (pthread_join(thread0, &result) == -1)
error("无法回收线程t0");
if (pthread_join(thread1, &result) == -1)
error("无法收回线程t1");
用一个变量接收线程返回的指针,然后针对线程调用函数pthread_join
。可以同时监听多个线程。这样主线程会在监听函数执行完之后才继续往下执行,这里就会结束。
完整的main
函数如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
int main(int argc, char* argv[])
{
pthread_t thread0;
pthread_t thread1;
//线程需要运行的函数传递给pthread_create
if (pthread_create(&thread0, NULL, overtime, NULL) == -1) {
error("can't create thread0");
}
if (pthread_create(&thread1, NULL, update_git, NULL) == -1) {
error("can't create thread1");
}
//用一个变量接收线程函数返回的指针
void *result;
//pthread_join通过监听线程返回值的方式等待线程
if (pthread_join(thread0, &result) == -1)
error("无法回收线程t0");
if (pthread_join(thread1, &result) == -1)
error("无法收回线程t1");
return 0;
}
这段代码也只能在linux下编译,需要链接库:
gcc main.c -o threads -lpthread
运行之后,可以看到两个线程的执行是乱序的。这也说明具体线程的执行顺序是不确定的。
老问题:线程间共享数据
线程就不像进程,fork的时候会复制全部的变量,然后彼此独立开来。线程依然在同一个进程内,共享同一个进程内的所有数据。
这也就导致如果不加以控制,线程操作数据的结果无法预料。最简单的不加锁的例子。
奇怪的是自己写了个尝试多线程读取变量的程序,发现运行结果竟然相同。。。
那就看加锁的情况吧:
//先初始化锁为不锁状态
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//在进入锁的地方:
if (pthread_mutex_lock(&mutex) != 0) {
perror("pthread_mutex_lock");
exit(EXIT_FAILURE);
}
//解锁
if (pthread_mutex_unlock(&mutex) != 0) {
perror("pthread_mutex_unlock");
exit(EXIT_FAILURE);
}
类似于锁的使用还有使用信号量,这个留待以后研究了。
后边的给线程传递一个函数似乎不起作用,在linux下编译运行通不过去,报内存错误。
估计问题主要还是出在指针和long类型的转换上。
系统编程的时候再来看吧。