1

Tclメインプログラムがあり、そこからCスレッドを作成したいと思います。次に、2つのスレッド間で情報を共有する必要があります。Cスレッドのプロセスは、入力/出力を頻繁に更新します。私の問題には2つの解決策があります。(1)Tclのスレッド共有変数をCに移植しましたが、TCL-CAPIにそれに関する情報が表示されませんでした。(2)Tcl-Cリンク変数を作成し、Cスレッド作成時に引数として使用します。後者のアイデアはうまくいかないようです。Cコードは次のとおりです。

#include <tcl.h>

/*
startRoutine
*/
static void startRoutine (ClientData clientData) {
 int *Var;
 Var= (int *) clientData;
 int locA=0;
 int j;
 int k;
 while (1) {    
     if (locA=!*Var) {
         // Modify Tcl-C shared variable
         locA=2 * *Var;
         *Var=locA;
         for (j=0; j<100; j++){}
     } else {
         for (k=0; k<100; k++){}
     }
  }
 }




static int
createThreadC_Cmd(
    ClientData cdata,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{

    // Contains the ID of the newly created thread
    Tcl_ThreadId id;    
    // Thread argument
    ClientData limitData;

    // Transfering global var argument to the created thread
    limitData=cdata;

    // Thread creation
    id=0;
    Tcl_CreateThread(&id, startRoutine, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);

    // Wait thread process, before returning to TCL prog
    int i;
    int aa;
    for (i=0 ; i<10000000 ; i++){
        aa=i;
    }

    // Return thread ID to tcl prog to allow mutex use
    Tcl_SetObjResult(interp, Tcl_NewIntObj((int) id));
    return TCL_OK;  
}


int DLLEXPORT

Behavcextension_Init(Tcl_Interp *interp)
{

    if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
        return TCL_ERROR;
    }

    // Create global Var
    int *sharedPtr;
    int linkedVar=0;
    sharedPtr=&linkedVar;
    Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);

    Tcl_CreateObjCommand(interp, 
        "createThreadC", createThreadC_Cmd, sharedPtr, NULL);
    return TCL_OK;

}

Tclコードは次のとおりです。

# linkedVar initial value in Tcl, will be overwritten by C Tcl_LinkVar() function
set linkedVar 98
puts "linkedVar: $linkedVar"

# Thread creation
#------------------
load [file join [pwd] libBehavCextension[info sharedlibextension]]
set threadId [createThreadC]
puts "Created thread $threadId, waiting"
# When Tcl_LinkVar() is called, initiate linkedVar at 2
puts "linkedVar: $linkedVar"

# Function inside thread should modify linkedVar into linkedVar*2
set linkedVar 98
after 5000
puts "linkedVar: $linkedVar"

ターミナル出力はここにあります:

Main thread ID: tid0xb779b6c0
linkedVar: 98
Created thread -1227252928, waiting
linkedVar: 2
linkedVar: 98

最終結果は2*98=196になります。TclとCの間のLinkVarの作成はOKです(リンクの作成後に2を取得します)が、LinkVarをスレッドに渡すのはKOです。それが機能しない理由/それを解決するために何をすべきかについての解決策や説明は大歓迎です!

4

1 に答える 1

1

問題は他の質問と同じままです。直後に終了する関数で、CスタックのC側の変数にストレージを割り当てています。関数()の終了後にその変数(にある)linkedVarを参照するのは未定義動作です。実際に発生するのは、実際のストレージが他の関数呼び出し(誰が何を知っているかを行う)に使用されるため、含まれる値は任意であり、それを変更すると「エキサイティングな」動作につながる可能性があります。Behavcextension_InitBehavcextension_Init

Behavcextension_Init終了後に存在する変数を探しているので、その関数のスタックに割り当ててはなりません。最も簡単な方法は次のとおりです。

int DLLEXPORT
Behavcextension_Init(Tcl_Interp *interp)
{
    int *sharedPtr;

    if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
        return TCL_ERROR;
    }

    sharedPtr = (int *) Tcl_Alloc(sizeof(int));  // Allocate
    *sharedPtr = 0;                              // Initialize
    Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);

    Tcl_CreateObjCommand(interp, 
        "createThreadC", createThreadC_Cmd, sharedPtr, NULL);
    return TCL_OK;
}

警告

  1. Tcl_Freeこれに一致するものがないため、これによりメモリリークが発生しTcl_Allocます。プロセスごとに1回割り当てられるメモリの場合、それはそれほど問題にはなりません。結局のところ、それはほんの数バイトであり、OSは終了時にそれを再利用します。
  2. これは、変数が書き込まれたスレッドとは異なるスレッドから変数を読み取る場合は安全ではありません。それが機能するという保証はありません。整数であるためおそらく機能しますが、協調するハードウェアに依存しています正しいことは、変数と適切なミューテックスの両方を含む構造を割り当て、ミューテックスを使用して変数へのアクセス(読み取りまたは書き込み)を保護することです。そのため、使用しない必要がありますTcl_LinkVar—ミューテックスで保護されたメモリについては何も知りません—しかし、Tclの変数間の結合を行うコールバックを提供するTcl_LinkVar単なるラッパーラウンドです(およびTcl_TraceVarTcl_GetVarTcl_SetVar)およびC変数; ミューテックス保護の処理方法も知っている自分で書くのは難しいことではありません。(興味がある場合は、ソースをTcl_LinkVar取得して自分で調整してください。プライベートAPI呼び出しは使用されません。)
于 2012-09-10T12:52:19.507 に答える