前言
如果使用多线程,就会涉及到并发问题,讨论并发问题。必然涉及到互斥与同步。
一 GMutex
相关的函数
初始化函数
void
g_mutex_init (GMutex *mutex);
上锁函数
void
g_mutex_lock (GMutex *mutex);
解锁函数
gboolean
g_mutex_trylock (GMutex *mutex);
g_mutex_clear ,这个函数,帮助信息上说,如果当前互斥锁处于锁定的状态,调用它会导致未知的事情发生。
g_mutex_clear ()
void
g_mutex_clear (GMutex *mutex);
Frees the resources allocated to a mutex with g_mutex_init().
This function should not be used with a GMutex that has been statically allocated.
Calling g_mutex_clear() on a locked mutex leads to undefined behaviour.
Sine: 2.32
Parameters
mutex
an initialized GMutex
写一段测试代码
#include <glib.h>
#include <gtimer.h>
#include <stdlib.h>
static int count = 0;
GMutex mutex;
gpointer my_thread_01(gpointer data)
{
int i = 0;
while(i < 1000){
i++;
g_mutex_lock(&mutex);
count++;
g_mutex_unlock(&mutex);
}
while(1){
g_usleep(1000);
}
}
gpointer my_thread_02(gpointer data)
{
int i = 0;
while(i < 1000){
i++;
g_mutex_lock(&mutex);
count++;
g_mutex_unlock(&mutex);
}
while(1){
g_usleep(1000);
}
}
gpointer my_thread_03(gpointer data)
{
int i = 0;
g_usleep(1000*1000);
g_print("count = %d\n",count);
while(1){
g_usleep(1000);
}
}
int main(void)
{
g_mutex_init (&mutex);
g_thread_new("my_thread_01",my_thread_01,NULL);
g_thread_new("my_thread_02",my_thread_02,NULL);
g_thread_new("my_thread_03",my_thread_03,NULL);
while(1){
g_usleep(1000);
}
return 0;
}
运行结果:好意外的输出了2000
使用pstree命令,毫无意外的看到了3个子线程。
root@ATK-IMX6U:~# pstree -p 19844
app(19844)─┬─{my_thread_01}(19845)
├─{my_thread_02}(19846)
└─{my_thread_03}(19847)
root@ATK-IMX6U:~#
如果在线程中添加如下代码
g_print("%d :%d\n",getppid(),getpid());
打印的内容如下:
16451 :24948
使用pstree查看16451的子进程,如下所示,这说明,虽然线程确实有一个单独的进程号,但是使用getpid的时候还是打印app本身的进程号。
root@ATK-IMX6U:~# pstree -p 16451
sh(16451)─┬─app(24948)─┬─{my_thread_01}(24949)
│ ├─{my_thread_02}(24950)
│ └─{my_thread_03}(24951)
└─pstree(25145)
root@ATK-IMX6U:~#
下面这种在一个线程加锁,在另一个线程解锁也是合法的。
static int count = 0;
GMutex mutex;
gpointer my_thread_01(gpointer data)
{
g_mutex_lock(&mutex);
while(1){
g_usleep(1000);
}
}
gpointer my_thread_02(gpointer data)
{
g_usleep(1000);
g_mutex_unlock(&mutex);
while(1){
g_usleep(1000);
}
}
二 GCond
初始化函数
void
g_cond_init (GCond *cond);
等待一个信号量
void
g_cond_wait (GCond *cond,
GMutex *mutex);
gboolean
g_cond_wait_until (GCond *cond,
GMutex *mutex,
gint64 end_time);
下面是一个官方例程:等待5秒,如果超时,g_cond_wait_until返回FALSE;end_time的值是当前的时间微秒数加上需要超时的时间微秒数。
#define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT (1000000))
gpointer
pop_data_timed (void)
{
gint64 end_time;
gpointer data;
g_mutex_lock (&data_mutex);
end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
while (!current_data)
if (!g_cond_wait_until (&data_cond, &data_mutex, end_time))
{
// timeout has passed.
g_mutex_unlock (&data_mutex);
return NULL;
}
// there is data for us
data = current_data;
current_data = NULL;
g_mutex_unlock (&data_mutex);
return data;
}
释放信号量
void
g_cond_signal (GCond *cond);
void
g_cond_broadcast (GCond *cond);
测试代码如下:
#include <glib.h>
#include <gtimer.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static int count = 0;
GMutex mutex;
GCond cond;
char buf[1024];
gpointer my_thread_01(gpointer data)
{
while(1){
g_mutex_lock(&mutex);
g_cond_wait(&cond,&mutex);
printf("buf = %s\n",buf);
memset(buf,0,sizeof(buf));
g_mutex_unlock(&mutex);
}
}
gpointer my_thread_02(gpointer data)
{
g_usleep(1);
while(1){
g_mutex_lock(&mutex);
g_print("wait for input:");
//while(strlen(buf) == 0){
scanf("%s",buf);
//}
g_print("send a signal:%s\n",buf);
//g_cond_broadcast(&cond);
g_cond_signal(&cond);
g_print("send a signal over\n",buf);
g_mutex_unlock(&mutex);
g_usleep(1000);
}
}
int main(void)
{
g_mutex_init (&mutex);
g_cond_init(&cond);
memset(buf,0,sizeof(buf));
g_thread_new("my_thread_01",my_thread_01,NULL);
g_thread_new("my_thread_02",my_thread_02,NULL);
while(1){
g_usleep(1000);
}
return 0;
}
执行效果:输入hello,线程01会获得信号,并输出hello,
在线程02函数运行后首先延时1微秒,如果不加延时,线程02先运行,线程01就获得不到锁,就运行不到g_cond_wait,就得不到输入端第一个字符串。
root@ATK-IMX6U:~# ./app
wait for input:hello
send a signal:hello
send a signal over
buf = hello
wait for input: