Thread 摘要

来源:互联网 发布:手机淘宝聊天工具 编辑:程序博客网 时间:2024/05/01 21:26

 Linux 线程 (From Internet)

GNU/Linux实现了标准的POSIX线程API,由线程库libpthread提供,相应的函数和数据类型申明在<pthread.h>中。

1、创建线程pthread_create():
-----------------
#include <pthread.h>
#include <stdio.h>
/* Prints x’s to stderr. The parameter is unused. Does not return. */
void* print_xs (void* par)
{
while (1)
fputc (*(char*)parm, stderr);
return NULL;
}
/* The main program. */
int main ()
{
pthread_t thread_id;
char par[1];
/* Create a new thread. The new thread will run the print_xs
function. */
par[0] = '0';
pthread_create (&thread_id, NULL, &print_xs, par);
return 0;
}
-----------------
新的线程创建以后,执行指定的函数。直到函数调用结束或者执行的过程中显示调用pthread_exit(),线程结束运行。
主、子线程独立调度。
在上面的例子中,如果主线程先运行结束,par所指的数据被释放,会造成子线程中内存访问错误。所以在向被创建线程的
执行程序传参数时要注意数据的生存有效期。

pthread_join()
防止上面错误程序的方法之一是在主线程的main()函数里调用pthread_join()等待子线程运行结束
-----------------
#include <pthread.h>
#include <stdio.h>
/* Prints x’s to stderr. The parameter is unused. Does not return. */
void* print_xs (void* par)
{
while (1)
fputc (*(char*)parm, stderr);
return NULL;
}
/* The main program. */
int main ()
{
pthread_t thread_id;
char par[1];
/* Create a new thread. The new thread will run the print_xs
function. */
par[0] = '0';
pthread_create (&thread_id, NULL, &print_xs, par);
pthread_join(thread_id);
return 0;
}
-----------------

2. 线程属性:pthread_attr_t
一般程序主要关注线程的detach state 属性。一个线程如果创建为joinable,则线程执行结束不会自动从系统中清除,直到有其他
线程调用pthread_join();一个线程如果创建为detached,则线程结束会自动从系统中清除。默认为joinable.
调用pthread_detach()可以将一个线程由jionable状态转变到detached状态。无法方向转变。
--------------
#include <pthread.h>
void* thread_function (void* thread_arg)
{
/* Do work here... */
}
int main ()
{
pthread_attr_t attr;
pthread_t thread;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&thread, &attr, &thread_function, NULL);
pthread_attr_destroy (&attr);
/* Do work here... */
/* No need to join the second thread. */
return 0;
}
-------------

3. 取消线程:pthread_cancel
在一个线程中调用pthread_cancel(tid)可以取消线程tid的执行。一个线程可以被同步取消/异步取消或不可取消。
具体参见<advanced linux programming> chapter 4.2

4.线程专有数据
同一个进程的线程具有相同的地址空间,共享代码和数据段。
但是线程的调用堆栈是独立的。除此以外Linux也提供了线程专有的数据区,通过pthread_key_create()及相关函数实现。
例:
------------
#include <malloc.h>
#include <pthread.h>
#include <stdio.h>

static pthread_key_t thread_data_key;

void write_thread_data ()
{
int* thread_data = (int*) pthread_getspecific (thread_data_key);

if (thread_data != NULL)
printf (“%d/n”, *thread_data);
}

/*To clean up thread-specific data*/
void clean_thread_data (void *thread_data)
{
if (thread_data != NULL)
free ((int *) thread_data);
}

void* thread_function (void* args)
{
int * thread_data;

thread_data = malloc (int);
pthread_setspecific (thread_data_key, thread_data);
write_thread_data ();
/* Do work here... */
return NULL;
}

int main ()
{
int i;
pthread_t threads[5];
/* Create a key to associate thread data in thread-specific data.
* clean_thread_data is called when thread exit;
*/
pthread_key_create (&thread_data_key, clean_thread_data);
/* Create threads to do the work. */
for (i = 0; i < 5; ++i)
pthread_create (&(threads[i]), NULL, thread_function, NULL);
/* Wait for all threads to finish. */
for (i = 0; i < 5; ++i)
pthread_join (threads[i], NULL);
return 0;
}
-------------
clean_thread_data 在线程执行结束时自动被调用,且传进thread_data_key对应的数据为参数。


5.共享访问
Linux提供互斥锁防止多线程访问共享数据造成的种种问题。
--------------
pthread_mutex_t mutex;
pthread_mutex_init (&mutex, NULL);
pthread_mutex_lock(&mutex); /*如果mutex没有被锁,锁之,返回。否则,被
block;*/
pthread_mutex_unlock(&mutex);
pthread_mutex_trylock(&mutex);/*如果mutex没有被锁,锁之,返回0。否则,返回参数EBUSY*/

信号量:
互斥锁解决解决竞争访问的问题(读者/写者),信号量则解决同步访问的问题(生产者/消费者);
-----------
sem_t sem;
sem_init (&sem, 0, 0);
sem_wait (&sem); /*如果sem 大于0,减1,放回;否则,block*/
sem_post (&sem); /*sem加1,如果有被block在sem上的线程,则某个被唤醒*/

条件变量:
Linux还提供条件变量来实现多线程访问的问题。
例:
---------
#include <pthread.h>
int thread_flag;
pthread_cond_t thread_flag_cv;
pthread_mutex_t thread_flag_mutex;
void initialize_flag ()
{
/* Initialize the mutex and condition variable. */
pthread_mutex_init (&thread_flag_mutex, NULL);
pthread_cond_init (&thread_flag_cv, NULL);
/* Initialize the flag value. */
thread_flag = 0;
}
/* Calls do_work repeatedly while the thread flag is set; blocks if
the flag is clear. */
void* thread_function (void* thread_arg)
{
/* Loop infinitely. */
while (1) {
/* Lock the mutex before accessing the flag value. */
pthread_mutex_lock (&thread_flag_mutex);
while (!thread_flag)
/* The flag is clear. Wait for a signal on the condition
variable, indicating that the flag value has changed. When the
signal arrives and this thread unblocks, loop and check the
flag again. */
pthread_cond_wait (&thread_flag_cv, &thread_flag_mutex);
/* When we’ve gotten here, we know the flag must be set. Unlock
the mutex. */
pthread_mutex_unlock (&thread_flag_mutex);
/* Do some work. */
do_work ();
}
return NULL;
}
/* Sets the value of the thread flag to FLAG_VALUE. */
void set_thread_flag (int flag_value)
{
/* Lock the mutex before accessing the flag value. */
pthread_mutex_lock (&thread_flag_mutex);
/* Set the flag value, and then signal in case thread_function is
blocked, waiting for the flag to become set. However,
thread_function can’t actually check the flag until the mutex is
unlocked. */
thread_flag = flag_value;
pthread_cond_signal (&thread_flag_cv);
/* Unlock the mutex. */
pthread_mutex_unlock (&thread_flag_mutex);
}
------------

6. Linux线程的实现
GNU/Linux线程是通过进程来实现的。这些进程共享地址空间和其他资源。
通过ps可以发现他们具有不同的pid。

事实上linux中的fork和pthread_create()都是通过系统调用clone()来实现的。
clone()可以让用户指定那些资源是在调用进程和新生进程中共享。
在应用程序编写中,建议直接使用fork()产生新进程,pthread_create()产生新线程。

原创粉丝点击