我正在研究一个学校项目(模拟虚拟内存),我们应该使用分离的线程。我们可以使用的还有其他限制,但我稍后会提到。问题是当我给pthread_create函数最后一个参数作为(void *)的东西并且创建的线程被分离时,pthread_create调用的函数将接收参数,但是由于线程被分离,原始参数会被删除作为我调用pthread_create的函数完成 - 这意味着被调用函数中的参数不再有效,因此我得到了分段错误等。这是代码的一部分(不能发布整个,它非常大):< / p>
bool CProcManager::NewProcess(void* processArg, void(*entryPoint)(CCPU*, void*), bool copyMem) {
uint32_t free_page;
pthread_attr_t attr;
pthread_t thread;
if (proc_cnt >= 63)
return 0;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (!FindFreePage(free_page)) return 0;
free_page = (free_page << 12) | 7;
CProcManager ccpu(m_MemStart, free_page);
ThrArgs args(entryPoint, (void *) processArg, ccpu);
proc_cnt++;
if (pthread_create(&thread, NULL, StartWork, (void *) &args))
return 0;
//pthread_mutex_lock(&start_mtx);
//pthread_cond_wait(&start_cond, &start_mtx);
//pthread_mutex_unlock(&start_mtx);
return 1;
}
在这里你可以看到这个函数有一个无效的poitner和一个指向函数作为参数的指针。 pthread_creates告诉线程调用&#34; StartWork&#34;带参数&#34; args&#34;的函数,它是一个包含指向函数的指针,指向void的指针和一个CProcManager类型的对象的结构。
void* CProcManager::StartWork(void* arguments) {
//pthread_mutex_lock(&start_mtx);
ThrArgs *args = (ThrArgs*) arguments;
CProcManager ccpu = args->ccpu;
//pthread_cond_signal(&start_cond);
//pthread_mutex_unlock(&start_mtx);
args->entryPoint(&ccpu, args->processArg);
ccpu.RemovePage((ccpu.m_PageTableRoot >> 12) * PAGE_SIZE, false);
pthread_mutex_lock(&end_mtx);
proc_cnt--;
pthread_cond_signal(&end_cond);
pthread_mutex_unlock(&end_mtx);
return (NULL);
}
在这个函数中,我终于调用了我有一个指针的函数。正如你猜测的那样,当&#34; NewProcess&#34;函数结束,所以我试图通过添加一个条件变量来克服这一点,并以某种方式复制我所拥有的参数(尚未找到解决方案),然后让&#34; NewProcess&#34;功能结束。但是这个项目有一定的局限性。功能&#34; NewProcess&#34;被调用很多次并且线程应该同时运行(我在调用entryPoint之后尝试发信号通知条件变量并且有效),所以我不能完成一个线程然后再执行下一个。参数&#34; void * processArg&#34;第一个函数最初是一个特定的对象类型,这个类型不能从上面的两个函数中访问。
所以有人可以给我一个建议如何复制参数,这样我就没有分离错误了吗?
答案 0 :(得分:1)
问题非常简单,是对象生命周期和所有权之一。
您正在传递&#39; args&#39;在线程,但&#39; args&#39;是在堆栈上创建的,并且在线程启动后很快就会超出范围。
做到这样的事情:
// note: The ThrArgs constructor should take ownership of processArg
std::unique_ptr<ThrArgs> args (new ThrArgs(entryPoint, (void *) processArg, ccpu));
if (pthread_create(&thread, NULL, StartWork, (void *) args.get())) {
args.release();
// ownership of the pointer now belongs to the thread
return 0;
}
然后在线程函数中:
void* CProcManager::StartWork(void* arguments) {
std::unique_ptr<ThrArgs> args (reinterpret_cast<ThrArgs*>(arguments));
// now use args as a pointer
....
// the arguments will be deleted here
return 0;
}
答案 1 :(得分:0)
有两种解决方案。最简单的通常就是分配
动态参数:NewProcess
:
ThrArgs* args = new ThrArgs( entryPoint, processArg, ccpu );
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if (!results) {
delete args;
}
(您可以在此处使用std::unique_ptr
或std::auto_ptr
好。在这种情况下,不要呼叫释放,除非
pthread_create
成功!)
另一种方法是创建一个条件变量
一个布尔值,然后在离开函数之前等待它,然后复制
参数然后在新线程中设置布尔值:in
NewProcess
:
pthread_mutex_lock( &theMutex );
freeToContinue = false;
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if ( results ) {
while ( !freeToContinue ) {
pthread_cond_wait( &theCond, &theMutex );
}
pthread_mutex_unlock( &theMutex );
}
return results;
和StartWork
(您传递给pthread_create
的功能
必须是extern "C"
,因此不能成为会员):
void* StartWork( void* arguments )
{
pthread_mutex_lock( &theMutex );
ThrArgs args = *static_cast<ThrArgs*>( arguments );
freeToContinue = true;
pthread_cond_broadcast( &theCond );
pthread_mutex_unlock( &theMutex );
// ...
}
(显然,我在这里遗漏了很多错误。)
无论哪种方式:你可能需要做类似的事情
processArg
参数,因为它的生命周期由
来电者。
并且您不需要将所有演员阵容都void*
。